remove luci luci-base openmptcprouter-full of repo
|
@ -1,52 +0,0 @@
|
|||
#
|
||||
# Copyright (C) 2008-2015 The LuCI Team <luci@lists.subsignal.org>
|
||||
#
|
||||
# This is free software, licensed under the Apache License, Version 2.0 .
|
||||
#
|
||||
|
||||
include $(TOPDIR)/rules.mk
|
||||
|
||||
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
|
||||
|
||||
|
||||
PKG_SOURCE:=v1.0.0.tar.gz
|
||||
PKG_SOURCE_URL:=https://github.com/jirutka/luasrcdiet/archive/
|
||||
PKG_HASH:=48162e63e77d009f5848f18a5cabffbdfc867d0e5e73c6d407f6af5d6880151b
|
||||
PKG_LICENSE:=MIT
|
||||
|
||||
HOST_BUILD_DIR:=$(BUILD_DIR_HOST)/luasrcdiet-1.0.0
|
||||
|
||||
include $(INCLUDE_DIR)/host-build.mk
|
||||
|
||||
define Package/luci-base/conffiles
|
||||
/etc/luci-uploads
|
||||
/etc/config/luci
|
||||
/etc/config/ucitrack
|
||||
endef
|
||||
|
||||
include ../luci/luci.mk
|
||||
|
||||
define Host/Configure
|
||||
endef
|
||||
|
||||
define Host/Compile
|
||||
$(MAKE) -C src/ clean po2lmo
|
||||
endef
|
||||
|
||||
define Host/Install
|
||||
$(INSTALL_DIR) $(1)/bin
|
||||
$(INSTALL_DIR) $(1)/lib/lua/5.1
|
||||
$(INSTALL_BIN) src/po2lmo $(1)/bin/po2lmo
|
||||
$(INSTALL_BIN) $(HOST_BUILD_DIR)/bin/luasrcdiet $(1)/bin/luasrcdiet
|
||||
$(CP) $(HOST_BUILD_DIR)/luasrcdiet $(1)/lib/lua/5.1/
|
||||
endef
|
||||
|
||||
$(eval $(call HostBuild))
|
||||
|
||||
# call BuildPackage - OpenWrt buildroot signature
|
|
@ -1,5 +0,0 @@
|
|||
#!/usr/bin/lua
|
||||
require "luci.cacheloader"
|
||||
require "luci.sgi.cgi"
|
||||
luci.dispatcher.indexcache = "/tmp/luci-indexcache"
|
||||
luci.sgi.cgi.run()
|
Before Width: | Height: | Size: 378 B |
Before Width: | Height: | Size: 268 B |
Before Width: | Height: | Size: 135 B |
Before Width: | Height: | Size: 131 B |
Before Width: | Height: | Size: 189 B |
Before Width: | Height: | Size: 272 B |
Before Width: | Height: | Size: 371 B |
Before Width: | Height: | Size: 267 B |
Before Width: | Height: | Size: 273 B |
Before Width: | Height: | Size: 698 B |
Before Width: | Height: | Size: 266 B |
Before Width: | Height: | Size: 230 B |
Before Width: | Height: | Size: 279 B |
Before Width: | Height: | Size: 248 B |
Before Width: | Height: | Size: 385 B |
Before Width: | Height: | Size: 258 B |
Before Width: | Height: | Size: 263 B |
Before Width: | Height: | Size: 130 B |
Before Width: | Height: | Size: 246 B |
Before Width: | Height: | Size: 706 B |
Before Width: | Height: | Size: 391 B |
Before Width: | Height: | Size: 681 B |
Before Width: | Height: | Size: 405 B |
Before Width: | Height: | Size: 701 B |
Before Width: | Height: | Size: 399 B |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 769 B |
Before Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 462 B |
Before Width: | Height: | Size: 439 B |
Before Width: | Height: | Size: 465 B |
Before Width: | Height: | Size: 467 B |
Before Width: | Height: | Size: 457 B |
Before Width: | Height: | Size: 639 B |
Before Width: | Height: | Size: 680 B |
Before Width: | Height: | Size: 398 B |
Before Width: | Height: | Size: 343 B |
Before Width: | Height: | Size: 235 B |
Before Width: | Height: | Size: 680 B |
Before Width: | Height: | Size: 398 B |
Before Width: | Height: | Size: 767 B |
Before Width: | Height: | Size: 494 B |
|
@ -1,268 +0,0 @@
|
|||
/*
|
||||
* xhr.js - XMLHttpRequest helper class
|
||||
* (c) 2008-2010 Jo-Philipp Wich
|
||||
*/
|
||||
|
||||
XHR = function()
|
||||
{
|
||||
this.reinit = function()
|
||||
{
|
||||
if (window.XMLHttpRequest) {
|
||||
this._xmlHttp = new XMLHttpRequest();
|
||||
}
|
||||
else if (window.ActiveXObject) {
|
||||
this._xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
|
||||
}
|
||||
else {
|
||||
alert("xhr.js: XMLHttpRequest is not supported by this browser!");
|
||||
}
|
||||
}
|
||||
|
||||
this.busy = function() {
|
||||
if (!this._xmlHttp)
|
||||
return false;
|
||||
|
||||
switch (this._xmlHttp.readyState)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this.abort = function() {
|
||||
if (this.busy())
|
||||
this._xmlHttp.abort();
|
||||
}
|
||||
|
||||
this.get = function(url,data,callback,timeout)
|
||||
{
|
||||
this.reinit();
|
||||
|
||||
var ts = Date.now();
|
||||
var xhr = this._xmlHttp;
|
||||
var code = this._encode(data);
|
||||
|
||||
url = location.protocol + '//' + location.host + url;
|
||||
|
||||
if (code)
|
||||
if (url.substr(url.length-1,1) == '&')
|
||||
url += code;
|
||||
else
|
||||
url += '?' + code;
|
||||
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
if (!isNaN(timeout))
|
||||
xhr.timeout = timeout;
|
||||
|
||||
xhr.onreadystatechange = function()
|
||||
{
|
||||
if (xhr.readyState == 4) {
|
||||
var json = null;
|
||||
if (xhr.getResponseHeader("Content-Type") == "application/json") {
|
||||
try { json = JSON.parse(xhr.responseText); }
|
||||
catch(e) { json = null; }
|
||||
}
|
||||
|
||||
callback(xhr, json, Date.now() - ts);
|
||||
}
|
||||
}
|
||||
|
||||
xhr.send(null);
|
||||
}
|
||||
|
||||
this.post = function(url,data,callback,timeout)
|
||||
{
|
||||
this.reinit();
|
||||
|
||||
var ts = Date.now();
|
||||
var xhr = this._xmlHttp;
|
||||
var code = this._encode(data);
|
||||
|
||||
xhr.onreadystatechange = function()
|
||||
{
|
||||
if (xhr.readyState == 4) {
|
||||
var json = null;
|
||||
if (xhr.getResponseHeader("Content-Type") == "application/json") {
|
||||
try { json = JSON.parse(xhr.responseText); }
|
||||
catch(e) { json = null; }
|
||||
}
|
||||
|
||||
callback(xhr, json, Date.now() - ts);
|
||||
}
|
||||
}
|
||||
|
||||
xhr.open('POST', url, true);
|
||||
|
||||
if (!isNaN(timeout))
|
||||
xhr.timeout = timeout;
|
||||
|
||||
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
|
||||
xhr.send(code);
|
||||
}
|
||||
|
||||
this.cancel = function()
|
||||
{
|
||||
this._xmlHttp.onreadystatechange = function(){};
|
||||
this._xmlHttp.abort();
|
||||
}
|
||||
|
||||
this.send_form = function(form,callback,extra_values)
|
||||
{
|
||||
var code = '';
|
||||
|
||||
for (var i = 0; i < form.elements.length; i++)
|
||||
{
|
||||
var e = form.elements[i];
|
||||
|
||||
if (e.options)
|
||||
{
|
||||
code += (code ? '&' : '') +
|
||||
form.elements[i].name + '=' + encodeURIComponent(
|
||||
e.options[e.selectedIndex].value
|
||||
);
|
||||
}
|
||||
else if (e.length)
|
||||
{
|
||||
for (var j = 0; j < e.length; j++)
|
||||
if (e[j].name) {
|
||||
code += (code ? '&' : '') +
|
||||
e[j].name + '=' + encodeURIComponent(e[j].value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
code += (code ? '&' : '') +
|
||||
e.name + '=' + encodeURIComponent(e.value);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof extra_values == 'object')
|
||||
for (var key in extra_values)
|
||||
code += (code ? '&' : '') +
|
||||
key + '=' + encodeURIComponent(extra_values[key]);
|
||||
|
||||
return(
|
||||
(form.method == 'get')
|
||||
? this.get(form.getAttribute('action'), code, callback)
|
||||
: this.post(form.getAttribute('action'), code, callback)
|
||||
);
|
||||
}
|
||||
|
||||
this._encode = function(obj)
|
||||
{
|
||||
obj = obj ? obj : { };
|
||||
obj['_'] = Math.random();
|
||||
|
||||
if (typeof obj == 'object')
|
||||
{
|
||||
var code = '';
|
||||
var self = this;
|
||||
|
||||
for (var k in obj)
|
||||
code += (code ? '&' : '') +
|
||||
k + '=' + encodeURIComponent(obj[k]);
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
XHR.get = function(url, data, callback)
|
||||
{
|
||||
(new XHR()).get(url, data, callback);
|
||||
}
|
||||
|
||||
XHR.poll = function(interval, url, data, callback, post)
|
||||
{
|
||||
if (isNaN(interval) || interval < 1)
|
||||
interval = 5;
|
||||
|
||||
if (!XHR._q)
|
||||
{
|
||||
XHR._t = 0;
|
||||
XHR._q = [ ];
|
||||
XHR._r = function() {
|
||||
for (var i = 0, e = XHR._q[0]; i < XHR._q.length; e = XHR._q[++i])
|
||||
{
|
||||
if (!(XHR._t % e.interval) && !e.xhr.busy())
|
||||
e.xhr[post ? 'post' : 'get'](e.url, e.data, e.callback, e.interval * 1000 * 5 - 5);
|
||||
}
|
||||
|
||||
XHR._t++;
|
||||
};
|
||||
}
|
||||
|
||||
var e = {
|
||||
interval: interval,
|
||||
callback: callback,
|
||||
url: url,
|
||||
data: data,
|
||||
xhr: new XHR()
|
||||
};
|
||||
|
||||
XHR._q.push(e);
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
XHR.stop = function(e)
|
||||
{
|
||||
for (var i = 0; XHR._q && XHR._q[i]; i++) {
|
||||
if (XHR._q[i] === e) {
|
||||
e.xhr.cancel();
|
||||
XHR._q.splice(i, 1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
XHR.halt = function()
|
||||
{
|
||||
if (XHR._i)
|
||||
{
|
||||
/* show & set poll indicator */
|
||||
try {
|
||||
document.getElementById('xhr_poll_status').style.display = '';
|
||||
document.getElementById('xhr_poll_status_on').style.display = 'none';
|
||||
document.getElementById('xhr_poll_status_off').style.display = '';
|
||||
} catch(e) { }
|
||||
|
||||
window.clearInterval(XHR._i);
|
||||
XHR._i = null;
|
||||
}
|
||||
}
|
||||
|
||||
XHR.run = function()
|
||||
{
|
||||
if (XHR._r && !XHR._i)
|
||||
{
|
||||
/* show & set poll indicator */
|
||||
try {
|
||||
document.getElementById('xhr_poll_status').style.display = '';
|
||||
document.getElementById('xhr_poll_status_on').style.display = '';
|
||||
document.getElementById('xhr_poll_status_off').style.display = 'none';
|
||||
} catch(e) { }
|
||||
|
||||
/* kick first round manually to prevent one second lag when setting up
|
||||
* the poll interval */
|
||||
XHR._r();
|
||||
XHR._i = window.setInterval(XHR._r, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
XHR.running = function()
|
||||
{
|
||||
return !!(XHR._r && XHR._i);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', XHR.run);
|
|
@ -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.
|
||||
|
||||
local config = require "luci.config"
|
||||
local ccache = require "luci.ccache"
|
||||
|
||||
module "luci.cacheloader"
|
||||
|
||||
if config.ccache and config.ccache.enable == "1" then
|
||||
ccache.cache_ondemand()
|
||||
end
|
|
@ -1,462 +0,0 @@
|
|||
-- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Copyright 2017 Dan Luedtke <mail@danrl.com>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local fs = require "nixio.fs"
|
||||
local ip = require "luci.ip"
|
||||
local math = require "math"
|
||||
local util = require "luci.util"
|
||||
local tonumber, tostring, type, unpack, select = tonumber, tostring, type, unpack, select
|
||||
|
||||
|
||||
module "luci.cbi.datatypes"
|
||||
|
||||
|
||||
_M['or'] = function(v, ...)
|
||||
local i
|
||||
for i = 1, select('#', ...), 2 do
|
||||
local f = select(i, ...)
|
||||
local a = select(i+1, ...)
|
||||
if type(f) ~= "function" then
|
||||
if f == v then
|
||||
return true
|
||||
end
|
||||
i = i - 1
|
||||
elseif f(v, unpack(a)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
_M['and'] = function(v, ...)
|
||||
local i
|
||||
for i = 1, select('#', ...), 2 do
|
||||
local f = select(i, ...)
|
||||
local a = select(i+1, ...)
|
||||
if type(f) ~= "function" then
|
||||
if f ~= v then
|
||||
return false
|
||||
end
|
||||
i = i - 1
|
||||
elseif not f(v, unpack(a)) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function neg(v, ...)
|
||||
return _M['or'](v:gsub("^%s*!%s*", ""), ...)
|
||||
end
|
||||
|
||||
function list(v, subvalidator, subargs)
|
||||
if type(subvalidator) ~= "function" then
|
||||
return false
|
||||
end
|
||||
local token
|
||||
for token in v:gmatch("%S+") do
|
||||
if not subvalidator(token, unpack(subargs)) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function bool(val)
|
||||
if val == "1" or val == "yes" or val == "on" or val == "true" then
|
||||
return true
|
||||
elseif val == "0" or val == "no" or val == "off" or val == "false" then
|
||||
return true
|
||||
elseif val == "" or val == nil then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function uinteger(val)
|
||||
local n = tonumber(val)
|
||||
if n ~= nil and math.floor(n) == n and n >= 0 then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function integer(val)
|
||||
local n = tonumber(val)
|
||||
if n ~= nil and math.floor(n) == n then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ufloat(val)
|
||||
local n = tonumber(val)
|
||||
return ( n ~= nil and n >= 0 )
|
||||
end
|
||||
|
||||
function float(val)
|
||||
return ( tonumber(val) ~= nil )
|
||||
end
|
||||
|
||||
function ipaddr(val)
|
||||
return ip4addr(val) or ip6addr(val)
|
||||
end
|
||||
|
||||
function ip4addr(val)
|
||||
if val then
|
||||
return ip.IPv4(val) and true or false
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ip4prefix(val)
|
||||
val = tonumber(val)
|
||||
return ( val and val >= 0 and val <= 32 )
|
||||
end
|
||||
|
||||
function ip6addr(val)
|
||||
if val then
|
||||
return ip.IPv6(val) and true or false
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function ip6prefix(val)
|
||||
val = tonumber(val)
|
||||
return ( val and val >= 0 and val <= 128 )
|
||||
end
|
||||
|
||||
function cidr4(val)
|
||||
local ip, mask = val:match("^([^/]+)/([^/]+)$")
|
||||
|
||||
return ip4addr(ip) and ip4prefix(mask)
|
||||
end
|
||||
|
||||
function cidr6(val)
|
||||
local ip, mask = val:match("^([^/]+)/([^/]+)$")
|
||||
|
||||
return ip6addr(ip) and ip6prefix(mask)
|
||||
end
|
||||
|
||||
function ipnet4(val)
|
||||
local ip, mask = val:match("^([^/]+)/([^/]+)$")
|
||||
|
||||
return ip4addr(ip) and ip4addr(mask)
|
||||
end
|
||||
|
||||
function ipnet6(val)
|
||||
local ip, mask = val:match("^([^/]+)/([^/]+)$")
|
||||
|
||||
return ip6addr(ip) and ip6addr(mask)
|
||||
end
|
||||
|
||||
function ipmask(val)
|
||||
return ipmask4(val) or ipmask6(val)
|
||||
end
|
||||
|
||||
function ipmask4(val)
|
||||
return cidr4(val) or ipnet4(val) or ip4addr(val)
|
||||
end
|
||||
|
||||
function ipmask6(val)
|
||||
return cidr6(val) or ipnet6(val) or ip6addr(val)
|
||||
end
|
||||
|
||||
function ip6hostid(val)
|
||||
if val == "eui64" or val == "random" then
|
||||
return true
|
||||
else
|
||||
local addr = ip.IPv6(val)
|
||||
if addr and addr:prefix() == 128 and addr:lower("::1:0:0:0:0") then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function port(val)
|
||||
val = tonumber(val)
|
||||
return ( val and val >= 0 and val <= 65535 )
|
||||
end
|
||||
|
||||
function portrange(val)
|
||||
local p1, p2 = val:match("^(%d+)%-(%d+)$")
|
||||
if p1 and p2 and port(p1) and port(p2) then
|
||||
return true
|
||||
else
|
||||
return port(val)
|
||||
end
|
||||
end
|
||||
|
||||
function macaddr(val)
|
||||
return ip.checkmac(val) and true or false
|
||||
end
|
||||
|
||||
function hostname(val, strict)
|
||||
if val and (#val < 254) and (
|
||||
val:match("^[a-zA-Z_]+$") or
|
||||
(val:match("^[a-zA-Z0-9_][a-zA-Z0-9_%-%.]*[a-zA-Z0-9]$") and
|
||||
val:match("[^0-9%.]"))
|
||||
) then
|
||||
return (not strict or not val:match("^_"))
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function host(val, ipv4only)
|
||||
return hostname(val) or ((ipv4only == 1) and ip4addr(val)) or ((not (ipv4only == 1)) and ipaddr(val))
|
||||
end
|
||||
|
||||
function network(val)
|
||||
return uciname(val) or host(val)
|
||||
end
|
||||
|
||||
function hostport(val, ipv4only)
|
||||
local h, p = val:match("^([^:]+):([^:]+)$")
|
||||
return not not (h and p and host(h, ipv4only) and port(p))
|
||||
end
|
||||
|
||||
function ip4addrport(val, bracket)
|
||||
local h, p = val:match("^([^:]+):([^:]+)$")
|
||||
return (h and p and ip4addr(h) and port(p))
|
||||
end
|
||||
|
||||
function ip4addrport(val)
|
||||
local h, p = val:match("^([^:]+):([^:]+)$")
|
||||
return (h and p and ip4addr(h) and port(p))
|
||||
end
|
||||
|
||||
function ipaddrport(val, bracket)
|
||||
local h, p = val:match("^([^%[%]:]+):([^:]+)$")
|
||||
if (h and p and ip4addr(h) and port(p)) then
|
||||
return true
|
||||
elseif (bracket == 1) then
|
||||
h, p = val:match("^%[(.+)%]:([^:]+)$")
|
||||
if (h and p and ip6addr(h) and port(p)) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
h, p = val:match("^([^%[%]]+):([^:]+)$")
|
||||
return (h and p and ip6addr(h) and port(p))
|
||||
end
|
||||
|
||||
function wpakey(val)
|
||||
if #val == 64 then
|
||||
return (val:match("^[a-fA-F0-9]+$") ~= nil)
|
||||
else
|
||||
return (#val >= 8) and (#val <= 63)
|
||||
end
|
||||
end
|
||||
|
||||
function wepkey(val)
|
||||
if val:sub(1, 2) == "s:" then
|
||||
val = val:sub(3)
|
||||
end
|
||||
|
||||
if (#val == 10) or (#val == 26) then
|
||||
return (val:match("^[a-fA-F0-9]+$") ~= nil)
|
||||
else
|
||||
return (#val == 5) or (#val == 13)
|
||||
end
|
||||
end
|
||||
|
||||
function hexstring(val)
|
||||
if val then
|
||||
return (val:match("^[a-fA-F0-9]+$") ~= nil)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function hex(val, maxbytes)
|
||||
maxbytes = tonumber(maxbytes)
|
||||
if val and maxbytes ~= nil then
|
||||
return ((val:match("^0x[a-fA-F0-9]+$") ~= nil) and (#val <= 2 + maxbytes * 2))
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function base64(val)
|
||||
if val then
|
||||
return (val:match("^[a-zA-Z0-9/+]+=?=?$") ~= nil) and (math.fmod(#val, 4) == 0)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function string(val)
|
||||
return true -- Everything qualifies as valid string
|
||||
end
|
||||
|
||||
function directory(val, seen)
|
||||
local s = fs.stat(val)
|
||||
seen = seen or { }
|
||||
|
||||
if s and not seen[s.ino] then
|
||||
seen[s.ino] = true
|
||||
if s.type == "dir" then
|
||||
return true
|
||||
elseif s.type == "lnk" then
|
||||
return directory( fs.readlink(val), seen )
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function file(val, seen)
|
||||
local s = fs.stat(val)
|
||||
seen = seen or { }
|
||||
|
||||
if s and not seen[s.ino] then
|
||||
seen[s.ino] = true
|
||||
if s.type == "reg" then
|
||||
return true
|
||||
elseif s.type == "lnk" then
|
||||
return file( fs.readlink(val), seen )
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function device(val, seen)
|
||||
local s = fs.stat(val)
|
||||
seen = seen or { }
|
||||
|
||||
if s and not seen[s.ino] then
|
||||
seen[s.ino] = true
|
||||
if s.type == "chr" or s.type == "blk" then
|
||||
return true
|
||||
elseif s.type == "lnk" then
|
||||
return device( fs.readlink(val), seen )
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function uciname(val)
|
||||
return (val:match("^[a-zA-Z0-9_]+$") ~= nil)
|
||||
end
|
||||
|
||||
function range(val, min, max)
|
||||
val = tonumber(val)
|
||||
min = tonumber(min)
|
||||
max = tonumber(max)
|
||||
|
||||
if val ~= nil and min ~= nil and max ~= nil then
|
||||
return ((val >= min) and (val <= max))
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function min(val, min)
|
||||
val = tonumber(val)
|
||||
min = tonumber(min)
|
||||
|
||||
if val ~= nil and min ~= nil then
|
||||
return (val >= min)
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function max(val, max)
|
||||
val = tonumber(val)
|
||||
max = tonumber(max)
|
||||
|
||||
if val ~= nil and max ~= nil then
|
||||
return (val <= max)
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function rangelength(val, min, max)
|
||||
val = tostring(val)
|
||||
min = tonumber(min)
|
||||
max = tonumber(max)
|
||||
|
||||
if val ~= nil and min ~= nil and max ~= nil then
|
||||
return ((#val >= min) and (#val <= max))
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function minlength(val, min)
|
||||
val = tostring(val)
|
||||
min = tonumber(min)
|
||||
|
||||
if val ~= nil and min ~= nil then
|
||||
return (#val >= min)
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function maxlength(val, max)
|
||||
val = tostring(val)
|
||||
max = tonumber(max)
|
||||
|
||||
if val ~= nil and max ~= nil then
|
||||
return (#val <= max)
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function phonedigit(val)
|
||||
return (val:match("^[0-9\*#!%.]+$") ~= nil)
|
||||
end
|
||||
|
||||
function timehhmmss(val)
|
||||
return (val:match("^[0-6][0-9]:[0-6][0-9]:[0-6][0-9]$") ~= nil)
|
||||
end
|
||||
|
||||
function dateyyyymmdd(val)
|
||||
if val ~= nil then
|
||||
yearstr, monthstr, daystr = val:match("^(%d%d%d%d)-(%d%d)-(%d%d)$")
|
||||
if (yearstr == nil) or (monthstr == nil) or (daystr == nil) then
|
||||
return false;
|
||||
end
|
||||
year = tonumber(yearstr)
|
||||
month = tonumber(monthstr)
|
||||
day = tonumber(daystr)
|
||||
if (year == nil) or (month == nil) or (day == nil) then
|
||||
return false;
|
||||
end
|
||||
|
||||
local days_in_month = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
|
||||
|
||||
local function is_leap_year(year)
|
||||
return (year % 4 == 0) and ((year % 100 ~= 0) or (year % 400 == 0))
|
||||
end
|
||||
|
||||
function get_days_in_month(month, year)
|
||||
if (month == 2) and is_leap_year(year) then
|
||||
return 29
|
||||
else
|
||||
return days_in_month[month]
|
||||
end
|
||||
end
|
||||
if (year < 2015) then
|
||||
return false
|
||||
end
|
||||
if ((month == 0) or (month > 12)) then
|
||||
return false
|
||||
end
|
||||
if ((day == 0) or (day > get_days_in_month(month, year))) then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
|
@ -1,76 +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.
|
||||
|
||||
local io = require "io"
|
||||
local fs = require "nixio.fs"
|
||||
local util = require "luci.util"
|
||||
local nixio = require "nixio"
|
||||
local debug = require "debug"
|
||||
local string = require "string"
|
||||
local package = require "package"
|
||||
|
||||
local type, loadfile = type, loadfile
|
||||
|
||||
|
||||
module "luci.ccache"
|
||||
|
||||
function cache_ondemand(...)
|
||||
if debug.getinfo(1, 'S').source ~= "=?" then
|
||||
cache_enable(...)
|
||||
end
|
||||
end
|
||||
|
||||
function cache_enable(cachepath, mode)
|
||||
cachepath = cachepath or "/tmp/luci-modulecache"
|
||||
mode = mode or "r--r--r--"
|
||||
|
||||
local loader = package.loaders[2]
|
||||
local uid = nixio.getuid()
|
||||
|
||||
if not fs.stat(cachepath) then
|
||||
fs.mkdir(cachepath)
|
||||
end
|
||||
|
||||
local function _encode_filename(name)
|
||||
local encoded = ""
|
||||
for i=1, #name do
|
||||
encoded = encoded .. ("%2X" % string.byte(name, i))
|
||||
end
|
||||
return encoded
|
||||
end
|
||||
|
||||
local function _load_sane(file)
|
||||
local stat = fs.stat(file)
|
||||
if stat and stat.uid == uid and stat.modestr == mode then
|
||||
return loadfile(file)
|
||||
end
|
||||
end
|
||||
|
||||
local function _write_sane(file, func)
|
||||
if nixio.getuid() == uid then
|
||||
local fp = io.open(file, "w")
|
||||
if fp then
|
||||
fp:write(util.get_bytecode(func))
|
||||
fp:close()
|
||||
fs.chmod(file, mode)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
package.loaders[2] = function(mod)
|
||||
local encoded = cachepath .. "/" .. _encode_filename(mod)
|
||||
local modcons = _load_sane(encoded)
|
||||
|
||||
if modcons then
|
||||
return modcons
|
||||
end
|
||||
|
||||
-- No cachefile
|
||||
modcons = loader(mod)
|
||||
if type(modcons) == "function" then
|
||||
_write_sane(encoded, modcons)
|
||||
end
|
||||
return modcons
|
||||
end
|
||||
end
|
|
@ -1,18 +0,0 @@
|
|||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local util = require "luci.util"
|
||||
module("luci.config",
|
||||
function(m)
|
||||
if pcall(require, "luci.model.uci") then
|
||||
local config = util.threadlocal()
|
||||
setmetatable(m, {
|
||||
__index = function(tbl, key)
|
||||
if not config[key] then
|
||||
config[key] = luci.model.uci.cursor():get_all("luci", key)
|
||||
end
|
||||
return config[key]
|
||||
end
|
||||
})
|
||||
end
|
||||
end)
|
|
@ -1,37 +0,0 @@
|
|||
local debug = require "debug"
|
||||
local io = require "io"
|
||||
local collectgarbage, floor = collectgarbage, math.floor
|
||||
|
||||
module "luci.debug"
|
||||
__file__ = debug.getinfo(1, 'S').source:sub(2)
|
||||
|
||||
-- Enables the memory tracer with given flags and returns a function to disable the tracer again
|
||||
function trap_memtrace(flags, dest)
|
||||
flags = flags or "clr"
|
||||
local tracefile = io.open(dest or "/tmp/memtrace", "w")
|
||||
local peak = 0
|
||||
|
||||
local function trap(what, line)
|
||||
local info = debug.getinfo(2, "Sn")
|
||||
local size = floor(collectgarbage("count"))
|
||||
if size > peak then
|
||||
peak = size
|
||||
end
|
||||
if tracefile then
|
||||
tracefile:write(
|
||||
"[", what, "] ", info.source, ":", (line or "?"), "\t",
|
||||
(info.namewhat or ""), "\t",
|
||||
(info.name or ""), "\t",
|
||||
size, " (", peak, ")\n"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
debug.sethook(trap, flags)
|
||||
|
||||
return function()
|
||||
debug.sethook()
|
||||
tracefile:close()
|
||||
end
|
||||
end
|
||||
|
|
@ -1,229 +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 childs 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
|
||||
]]
|
||||
|
||||
---[[
|
||||
Register a tree modifier.
|
||||
|
||||
@class function
|
||||
@name modifier
|
||||
@param func Modifier function
|
||||
@param order Modifier order value (optional)
|
||||
]]
|
||||
|
||||
---[[
|
||||
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 _
|
||||
]]
|
||||
|
|
@ -1,554 +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 nixio = require "nixio"
|
||||
local ltn12 = require "luci.ltn12"
|
||||
|
||||
local table, ipairs, pairs, type, tostring, tonumber, error =
|
||||
table, ipairs, pairs, type, tostring, tonumber, 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
|
||||
end
|
||||
|
||||
function content()
|
||||
return context.request:content()
|
||||
end
|
||||
|
||||
function formvalue(name, noparse)
|
||||
return context.request:formvalue(name, noparse)
|
||||
end
|
||||
|
||||
function formvaluetable(prefix)
|
||||
return context.request:formvaluetable(prefix)
|
||||
end
|
||||
|
||||
function getcookie(name)
|
||||
return context.request:getcookie(name)
|
||||
end
|
||||
|
||||
-- or the environment table itself.
|
||||
function getenv(name)
|
||||
return context.request:getenv(name)
|
||||
end
|
||||
|
||||
function setfilehandler(callback)
|
||||
return context.request: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)
|
||||
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
|
||||
end
|
||||
|
||||
function source()
|
||||
return context.request.input
|
||||
end
|
||||
|
||||
function status(code, message)
|
||||
code = code or 200
|
||||
message = message or "OK"
|
||||
context.status = code
|
||||
coroutine.yield(1, 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
|
||||
end
|
||||
end
|
||||
|
||||
function splice(fd, size)
|
||||
coroutine.yield(6, fd, size)
|
||||
end
|
||||
|
||||
function redirect(url)
|
||||
if url == "" then url = "/" end
|
||||
status(302, "Found")
|
||||
header("Location", url)
|
||||
close()
|
||||
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)
|
||||
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
|
||||
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
|
||||
|
||||
-- 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 feeded 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 wheather 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
|
|
@ -1,260 +0,0 @@
|
|||
---[[
|
||||
LuCI Web Framework high-level HTTP functions.
|
||||
]]
|
||||
module "luci.http"
|
||||
|
||||
---[[
|
||||
Close the HTTP-Connection.
|
||||
|
||||
@class function
|
||||
@name close
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return the request content if the request was of unknown type.
|
||||
|
||||
@class function
|
||||
@name content
|
||||
@return HTTP request body
|
||||
@return HTTP request body length
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get a certain HTTP input value or a table of all input values.
|
||||
|
||||
@class function
|
||||
@name formvalue
|
||||
@param name Name of the GET or POST variable to fetch
|
||||
@param noparse Don't parse POST data before getting the value
|
||||
@return HTTP input value or table of all input value
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get a table of all HTTP input values with a certain prefix.
|
||||
|
||||
@class function
|
||||
@name formvaluetable
|
||||
@param prefix Prefix
|
||||
@return Table of all HTTP input values with given prefix
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get the value of a certain HTTP-Cookie.
|
||||
|
||||
@class function
|
||||
@name getcookie
|
||||
@param name Cookie Name
|
||||
@return String containing cookie data
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get the value of a certain HTTP environment variable
|
||||
or the environment table itself.
|
||||
|
||||
@class function
|
||||
@name getenv
|
||||
@param name Environment variable
|
||||
@return HTTP environment value or environment table
|
||||
]]
|
||||
|
||||
---[[
|
||||
Set a handler function for incoming user file uploads.
|
||||
|
||||
@class function
|
||||
@name setfilehandler
|
||||
@param callback Handler function
|
||||
]]
|
||||
|
||||
---[[
|
||||
Send a HTTP-Header.
|
||||
|
||||
@class function
|
||||
@name header
|
||||
@param key Header key
|
||||
@param value Header value
|
||||
]]
|
||||
|
||||
---[[
|
||||
Set the mime type of following content data.
|
||||
|
||||
@class function
|
||||
@name prepare_content
|
||||
@param mime Mimetype of following content
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get the RAW HTTP input source
|
||||
|
||||
@class function
|
||||
@name source
|
||||
@return HTTP LTN12 source
|
||||
]]
|
||||
|
||||
---[[
|
||||
Set the HTTP status code and status message.
|
||||
|
||||
@class function
|
||||
@name status
|
||||
@param code Status code
|
||||
@param message Status message
|
||||
]]
|
||||
|
||||
---[[
|
||||
Send a chunk of content data to the client.
|
||||
|
||||
This function is as a valid LTN12 sink.
|
||||
If the content chunk is nil this function will automatically invoke close.
|
||||
|
||||
@class function
|
||||
@name write
|
||||
@param content Content chunk
|
||||
@param src_err Error object from source (optional)
|
||||
@see close
|
||||
]]
|
||||
|
||||
---[[
|
||||
Splice data from a filedescriptor to the client.
|
||||
|
||||
@class function
|
||||
@name splice
|
||||
@param fp File descriptor
|
||||
@param size Bytes to splice (optional)
|
||||
]]
|
||||
|
||||
---[[
|
||||
Redirects the client to a new URL and closes the connection.
|
||||
|
||||
@class function
|
||||
@name redirect
|
||||
@param url Target URL
|
||||
]]
|
||||
|
||||
---[[
|
||||
Create a querystring out of a table of key - value pairs.
|
||||
|
||||
@class function
|
||||
@name build_querystring
|
||||
@param table Query string source table
|
||||
@return Encoded HTTP query string
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return the URL-decoded equivalent of a string.
|
||||
|
||||
@class function
|
||||
@name urldecode
|
||||
@param str URL-encoded string
|
||||
@param no_plus Don't decode + to " "
|
||||
@return URL-decoded string
|
||||
@see urlencode
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return the URL-encoded equivalent of a string.
|
||||
|
||||
@class function
|
||||
@name urlencode
|
||||
@param str Source string
|
||||
@return URL-encoded string
|
||||
@see urldecode
|
||||
]]
|
||||
|
||||
---[[
|
||||
Send the given data as JSON encoded string.
|
||||
|
||||
@class function
|
||||
@name write_json
|
||||
@param data Data to send
|
||||
]]
|
||||
|
||||
---[[
|
||||
Extract and split urlencoded data pairs, separated bei either "&" or ";"
|
||||
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.
|
||||
|
||||
@class function
|
||||
@name urldecode_params
|
||||
@param url The url or string which contains x-www-urlencoded form data
|
||||
@param tbl Use the given table for storing values (optional)
|
||||
@return Table containing the urldecoded parameters
|
||||
@see urlencode_params
|
||||
]]
|
||||
|
||||
---[[
|
||||
Encode each key-value-pair in given table to x-www-urlencoded format,
|
||||
separated by "&".
|
||||
|
||||
Tables are encoded as parameters with multiple values by repeating the
|
||||
parameter name with each value.
|
||||
|
||||
@class function
|
||||
@name urlencode_params
|
||||
@param tbl Table with the values
|
||||
@return String containing encoded values
|
||||
@see urldecode_params
|
||||
]]
|
||||
|
||||
---[[
|
||||
Decode a mime encoded http message body with multipart/form-data 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 feeded 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 wheather the current chunk is the last one (eof)
|
||||
|
||||
@class function
|
||||
@name mimedecode_message_body
|
||||
@param src Ltn12 source function
|
||||
@param msg HTTP message object
|
||||
@param filecb File callback function (optional)
|
||||
@return Value indicating successful operation (not nil means "ok")
|
||||
@return String containing the error if unsuccessful
|
||||
@see parse_message_header
|
||||
]]
|
||||
|
||||
---[[
|
||||
Decode an urlencoded http message body with application/x-www-urlencoded
|
||||
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.
|
||||
|
||||
@class function
|
||||
@name urldecode_message_body
|
||||
@param src Ltn12 source function
|
||||
@param msg HTTP message object
|
||||
@return Value indicating successful operation (not nil means "ok")
|
||||
@return String containing the error if unsuccessful
|
||||
@see parse_message_header
|
||||
]]
|
||||
|
||||
---[[
|
||||
Try to extract and decode a http message body from the given ltn12 source.
|
||||
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.
|
||||
|
||||
@class function
|
||||
@name parse_message_body
|
||||
@param src Ltn12 source function
|
||||
@param msg HTTP message object
|
||||
@param filecb File data callback (optional, see mimedecode_message_body())
|
||||
@return Value indicating successful operation (not nil means "ok")
|
||||
@return String containing the error if unsuccessful
|
||||
@see parse_message_header
|
||||
]]
|
|
@ -1,55 +0,0 @@
|
|||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
module("luci.i18n", package.seeall)
|
||||
require("luci.util")
|
||||
|
||||
local tparser = require "luci.template.parser"
|
||||
|
||||
table = {}
|
||||
i18ndir = luci.util.libpath() .. "/i18n/"
|
||||
loaded = {}
|
||||
context = luci.util.threadlocal()
|
||||
default = "en"
|
||||
|
||||
function clear()
|
||||
end
|
||||
|
||||
function load(file, lang, force)
|
||||
end
|
||||
|
||||
-- Alternatively load the translation of the fallback language.
|
||||
function loadc(file, force)
|
||||
end
|
||||
|
||||
function setlanguage(lang)
|
||||
context.lang = lang:gsub("_", "-")
|
||||
context.parent = (context.lang:match("^([a-z][a-z])_"))
|
||||
if not tparser.load_catalog(context.lang, i18ndir) then
|
||||
if context.parent then
|
||||
tparser.load_catalog(context.parent, i18ndir)
|
||||
return context.parent
|
||||
end
|
||||
end
|
||||
return context.lang
|
||||
end
|
||||
|
||||
function translate(key)
|
||||
return tparser.translate(key) or key
|
||||
end
|
||||
|
||||
function translatef(key, ...)
|
||||
return tostring(translate(key)):format(...)
|
||||
end
|
||||
|
||||
-- and ensure that the returned value is a Lua string value.
|
||||
-- This is the same as calling <code>tostring(translate(...))</code>
|
||||
function string(key)
|
||||
return tostring(translate(key))
|
||||
end
|
||||
|
||||
-- Ensure that the returned value is a Lua string value.
|
||||
-- This is the same as calling <code>tostring(translatef(...))</code>
|
||||
function stringf(key, ...)
|
||||
return tostring(translate(key)):format(...)
|
||||
end
|
|
@ -1,84 +0,0 @@
|
|||
---[[
|
||||
LuCI translation library.
|
||||
]]
|
||||
module "luci.i18n"
|
||||
|
||||
---[[
|
||||
Clear the translation table.
|
||||
|
||||
|
||||
@class function
|
||||
@name clear
|
||||
]]
|
||||
|
||||
---[[
|
||||
Load a translation and copy its data into the translation table.
|
||||
|
||||
@class function
|
||||
@name load
|
||||
@param file Language file
|
||||
@param lang Two-letter language code
|
||||
@param force Force reload even if already loaded (optional)
|
||||
@return Success status
|
||||
]]
|
||||
|
||||
---[[
|
||||
Load a translation file using the default translation language.
|
||||
|
||||
Alternatively load the translation of the fallback language.
|
||||
@class function
|
||||
@name loadc
|
||||
@param file Language file
|
||||
@param force Force reload even if already loaded (optional)
|
||||
]]
|
||||
|
||||
---[[
|
||||
Set the context default translation language.
|
||||
|
||||
@class function
|
||||
@name setlanguage
|
||||
@param lang Two-letter language code
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return the translated value for a specific translation key.
|
||||
|
||||
@class function
|
||||
@name translate
|
||||
@param key Default translation text
|
||||
@return Translated string
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return the translated value for a specific translation key and use it as sprintf pattern.
|
||||
|
||||
@class function
|
||||
@name translatef
|
||||
@param key Default translation text
|
||||
@param ... Format parameters
|
||||
@return Translated and formatted string
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return the translated value for a specific translation key
|
||||
|
||||
and ensure that the returned value is a Lua string value.
|
||||
This is the same as calling <code>tostring(translate(...))</code>
|
||||
@class function
|
||||
@name string
|
||||
@param key Default translation text
|
||||
@return Translated string
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return the translated value for a specific translation key and use it as sprintf pattern.
|
||||
|
||||
Ensure that the returned value is a Lua string value.
|
||||
This is the same as calling <code>tostring(translatef(...))</code>
|
||||
@class function
|
||||
@name stringf
|
||||
@param key Default translation text
|
||||
@param ... Format parameters
|
||||
@return Translated and formatted string
|
||||
]]
|
||||
|
|
@ -1,316 +0,0 @@
|
|||
--[[
|
||||
LuaSocket 2.0.2 license
|
||||
Copyright <EFBFBD> 2004-2007 Diego Nehab
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
DEALINGS IN THE SOFTWARE.
|
||||
]]--
|
||||
--[[
|
||||
Changes made by LuCI project:
|
||||
* Renamed to luci.ltn12 to avoid collisions with luasocket
|
||||
* Added inline documentation
|
||||
]]--
|
||||
-----------------------------------------------------------------------------
|
||||
-- LTN12 - Filters, sources, sinks and pumps.
|
||||
-- LuaSocket toolkit.
|
||||
-- Author: Diego Nehab
|
||||
-- RCS ID: $Id$
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Declare module
|
||||
-----------------------------------------------------------------------------
|
||||
local string = require("string")
|
||||
local table = require("table")
|
||||
local base = _G
|
||||
|
||||
-- See http://lua-users.org/wiki/FiltersSourcesAndSinks for design concepts
|
||||
module("luci.ltn12")
|
||||
|
||||
filter = {}
|
||||
source = {}
|
||||
sink = {}
|
||||
pump = {}
|
||||
|
||||
-- 2048 seems to be better in windows...
|
||||
BLOCKSIZE = 2048
|
||||
_VERSION = "LTN12 1.0.1"
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Filter stuff
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- by passing it each chunk and updating a context between calls.
|
||||
function filter.cycle(low, ctx, extra)
|
||||
base.assert(low)
|
||||
return function(chunk)
|
||||
local ret
|
||||
ret, ctx = low(ctx, chunk, extra)
|
||||
return ret
|
||||
end
|
||||
end
|
||||
|
||||
-- (thanks to Wim Couwenberg)
|
||||
function filter.chain(...)
|
||||
local n = table.getn(arg)
|
||||
local top, index = 1, 1
|
||||
local retry = ""
|
||||
return function(chunk)
|
||||
retry = chunk and retry
|
||||
while true do
|
||||
if index == top then
|
||||
chunk = arg[index](chunk)
|
||||
if chunk == "" or top == n then return chunk
|
||||
elseif chunk then index = index + 1
|
||||
else
|
||||
top = top+1
|
||||
index = top
|
||||
end
|
||||
else
|
||||
chunk = arg[index](chunk or "")
|
||||
if chunk == "" then
|
||||
index = index - 1
|
||||
chunk = retry
|
||||
elseif chunk then
|
||||
if index == n then return chunk
|
||||
else index = index + 1 end
|
||||
else base.error("filter returned inappropriate nil") end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Source stuff
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
-- create an empty source
|
||||
local function empty()
|
||||
return nil
|
||||
end
|
||||
|
||||
function source.empty()
|
||||
return empty
|
||||
end
|
||||
|
||||
function source.error(err)
|
||||
return function()
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
function source.file(handle, io_err)
|
||||
if handle then
|
||||
return function()
|
||||
local chunk = handle:read(BLOCKSIZE)
|
||||
if chunk and chunk:len() == 0 then chunk = nil end
|
||||
if not chunk then handle:close() end
|
||||
return chunk
|
||||
end
|
||||
else return source.error(io_err or "unable to open file") end
|
||||
end
|
||||
|
||||
function source.simplify(src)
|
||||
base.assert(src)
|
||||
return function()
|
||||
local chunk, err_or_new = src()
|
||||
src = err_or_new or src
|
||||
if not chunk then return nil, err_or_new
|
||||
else return chunk end
|
||||
end
|
||||
end
|
||||
|
||||
function source.string(s)
|
||||
if s then
|
||||
local i = 1
|
||||
return function()
|
||||
local chunk = string.sub(s, i, i+BLOCKSIZE-1)
|
||||
i = i + BLOCKSIZE
|
||||
if chunk ~= "" then return chunk
|
||||
else return nil end
|
||||
end
|
||||
else return source.empty() end
|
||||
end
|
||||
|
||||
function source.rewind(src)
|
||||
base.assert(src)
|
||||
local t = {}
|
||||
return function(chunk)
|
||||
if not chunk then
|
||||
chunk = table.remove(t)
|
||||
if not chunk then return src()
|
||||
else return chunk end
|
||||
else
|
||||
t[#t+1] = chunk
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function source.chain(src, f)
|
||||
base.assert(src and f)
|
||||
local last_in, last_out = "", ""
|
||||
local state = "feeding"
|
||||
local err
|
||||
return function()
|
||||
if not last_out then
|
||||
base.error('source is empty!', 2)
|
||||
end
|
||||
while true do
|
||||
if state == "feeding" then
|
||||
last_in, err = src()
|
||||
if err then return nil, err end
|
||||
last_out = f(last_in)
|
||||
if not last_out then
|
||||
if last_in then
|
||||
base.error('filter returned inappropriate nil')
|
||||
else
|
||||
return nil
|
||||
end
|
||||
elseif last_out ~= "" then
|
||||
state = "eating"
|
||||
if last_in then last_in = "" end
|
||||
return last_out
|
||||
end
|
||||
else
|
||||
last_out = f(last_in)
|
||||
if last_out == "" then
|
||||
if last_in == "" then
|
||||
state = "feeding"
|
||||
else
|
||||
base.error('filter returned ""')
|
||||
end
|
||||
elseif not last_out then
|
||||
if last_in then
|
||||
base.error('filter returned inappropriate nil')
|
||||
else
|
||||
return nil
|
||||
end
|
||||
else
|
||||
return last_out
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Sources will be used one after the other, as if they were concatenated
|
||||
-- (thanks to Wim Couwenberg)
|
||||
function source.cat(...)
|
||||
local src = table.remove(arg, 1)
|
||||
return function()
|
||||
while src do
|
||||
local chunk, err = src()
|
||||
if chunk then return chunk end
|
||||
if err then return nil, err end
|
||||
src = table.remove(arg, 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Sink stuff
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
function sink.table(t)
|
||||
t = t or {}
|
||||
local f = function(chunk, err)
|
||||
if chunk then t[#t+1] = chunk end
|
||||
return 1
|
||||
end
|
||||
return f, t
|
||||
end
|
||||
|
||||
function sink.simplify(snk)
|
||||
base.assert(snk)
|
||||
return function(chunk, err)
|
||||
local ret, err_or_new = snk(chunk, err)
|
||||
if not ret then return nil, err_or_new end
|
||||
snk = err_or_new or snk
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
function sink.file(handle, io_err)
|
||||
if handle then
|
||||
return function(chunk, err)
|
||||
if not chunk then
|
||||
handle:close()
|
||||
return 1
|
||||
else return handle:write(chunk) end
|
||||
end
|
||||
else return sink.error(io_err or "unable to open file") end
|
||||
end
|
||||
|
||||
-- creates a sink that discards data
|
||||
local function null()
|
||||
return 1
|
||||
end
|
||||
|
||||
function sink.null()
|
||||
return null
|
||||
end
|
||||
|
||||
function sink.error(err)
|
||||
return function()
|
||||
return nil, err
|
||||
end
|
||||
end
|
||||
|
||||
function sink.chain(f, snk)
|
||||
base.assert(f and snk)
|
||||
return function(chunk, err)
|
||||
if chunk ~= "" then
|
||||
local filtered = f(chunk)
|
||||
local done = chunk and ""
|
||||
while true do
|
||||
local ret, snkerr = snk(filtered, err)
|
||||
if not ret then return nil, snkerr end
|
||||
if filtered == done then return 1 end
|
||||
filtered = f(done)
|
||||
end
|
||||
else return 1 end
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------------------------
|
||||
-- Pump stuff
|
||||
-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
function pump.step(src, snk)
|
||||
local chunk, src_err = src()
|
||||
local ret, snk_err = snk(chunk, src_err)
|
||||
if chunk and ret then return 1
|
||||
else return nil, src_err or snk_err end
|
||||
end
|
||||
|
||||
function pump.all(src, snk, step)
|
||||
base.assert(src and snk)
|
||||
step = step or pump.step
|
||||
while true do
|
||||
local ret, err = step(src, snk)
|
||||
if not ret then
|
||||
if err then return nil, err
|
||||
else return 1 end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
-- Copyright 2011-2012 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local map, section, net = ...
|
||||
local ifc = net:get_interface()
|
||||
|
||||
local hostname, accept_ra, send_rs
|
||||
local bcast, defaultroute, peerdns, dns, metric, clientid, vendorclass
|
||||
|
||||
|
||||
hostname = section:taboption("general", Value, "hostname",
|
||||
translate("Hostname to send when requesting DHCP"))
|
||||
|
||||
hostname.placeholder = luci.sys.hostname()
|
||||
hostname.datatype = "hostname"
|
||||
|
||||
|
||||
bcast = section:taboption("advanced", Flag, "broadcast",
|
||||
translate("Use broadcast flag"),
|
||||
translate("Required for certain ISPs, e.g. Charter with DOCSIS 3"))
|
||||
|
||||
bcast.default = bcast.disabled
|
||||
|
||||
|
||||
defaultroute = section:taboption("advanced", Flag, "defaultroute",
|
||||
translate("Use default gateway"),
|
||||
translate("If unchecked, no default route is configured"))
|
||||
|
||||
defaultroute.default = defaultroute.enabled
|
||||
|
||||
|
||||
peerdns = section:taboption("advanced", Flag, "peerdns",
|
||||
translate("Use DNS servers advertised by peer"),
|
||||
translate("If unchecked, the advertised DNS server addresses are ignored"))
|
||||
|
||||
peerdns.default = peerdns.enabled
|
||||
|
||||
|
||||
dns = section:taboption("advanced", DynamicList, "dns",
|
||||
translate("Use custom DNS servers"))
|
||||
|
||||
dns:depends("peerdns", "")
|
||||
dns.datatype = "ipaddr"
|
||||
dns.cast = "string"
|
||||
|
||||
|
||||
metric = section:taboption("advanced", Value, "metric",
|
||||
translate("Use gateway metric"))
|
||||
|
||||
metric.placeholder = "0"
|
||||
metric.datatype = "uinteger"
|
||||
|
||||
|
||||
clientid = section:taboption("advanced", Value, "clientid",
|
||||
translate("Client ID to send when requesting DHCP"))
|
||||
|
||||
|
||||
vendorclass = section:taboption("advanced", Value, "vendorid",
|
||||
translate("Vendor Class to send when requesting DHCP"))
|
||||
|
||||
|
||||
luci.tools.proto.opt_macaddr(section, ifc, translate("Override MAC address"))
|
||||
|
||||
|
||||
mtu = section:taboption("advanced", Value, "mtu", translate("Override MTU"))
|
||||
mtu.placeholder = "1500"
|
||||
mtu.datatype = "max(9200)"
|
|
@ -1,4 +0,0 @@
|
|||
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local map, section, net = ...
|
|
@ -1,97 +0,0 @@
|
|||
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local map, section, net = ...
|
||||
local ifc = net:get_interface()
|
||||
|
||||
local ipaddr, netmask, gateway, broadcast, dns, accept_ra, send_rs, ip6addr, ip6gw
|
||||
local mtu, metric
|
||||
|
||||
|
||||
ipaddr = section:taboption("general", Value, "ipaddr", translate("IPv4 address"))
|
||||
ipaddr.datatype = "ip4addr"
|
||||
|
||||
|
||||
netmask = section:taboption("general", Value, "netmask",
|
||||
translate("IPv4 netmask"))
|
||||
|
||||
netmask.datatype = "ip4addr"
|
||||
netmask:value("255.255.255.0")
|
||||
netmask:value("255.255.0.0")
|
||||
netmask:value("255.0.0.0")
|
||||
|
||||
|
||||
gateway = section:taboption("general", Value, "gateway", translate("IPv4 gateway"))
|
||||
gateway.datatype = "ip4addr"
|
||||
|
||||
|
||||
broadcast = section:taboption("general", Value, "broadcast", translate("IPv4 broadcast"))
|
||||
broadcast.datatype = "ip4addr"
|
||||
|
||||
|
||||
dns = section:taboption("general", DynamicList, "dns",
|
||||
translate("Use custom DNS servers"))
|
||||
|
||||
dns.datatype = "ipaddr"
|
||||
dns.cast = "string"
|
||||
|
||||
|
||||
if luci.model.network:has_ipv6() then
|
||||
|
||||
local ip6assign = section:taboption("general", Value, "ip6assign", translate("IPv6 assignment length"),
|
||||
translate("Assign a part of given length of every public IPv6-prefix to this interface"))
|
||||
ip6assign:value("", translate("disabled"))
|
||||
ip6assign:value("64")
|
||||
ip6assign.datatype = "max(64)"
|
||||
|
||||
local ip6hint = section:taboption("general", Value, "ip6hint", translate("IPv6 assignment hint"),
|
||||
translate("Assign prefix parts using this hexadecimal subprefix ID for this interface."))
|
||||
for i=33,64 do ip6hint:depends("ip6assign", i) end
|
||||
|
||||
ip6addr = section:taboption("general", Value, "ip6addr", translate("IPv6 address"))
|
||||
ip6addr.datatype = "ip6addr"
|
||||
ip6addr:depends("ip6assign", "")
|
||||
|
||||
|
||||
ip6gw = section:taboption("general", Value, "ip6gw", translate("IPv6 gateway"))
|
||||
ip6gw.datatype = "ip6addr"
|
||||
ip6gw:depends("ip6assign", "")
|
||||
|
||||
|
||||
local ip6prefix = s:taboption("general", Value, "ip6prefix", translate("IPv6 routed prefix"),
|
||||
translate("Public prefix routed to this device for distribution to clients."))
|
||||
ip6prefix.datatype = "ip6addr"
|
||||
ip6prefix:depends("ip6assign", "")
|
||||
|
||||
local ip6ifaceid = s:taboption("general", Value, "ip6ifaceid", translate("IPv6 suffix"),
|
||||
translate("Optional. Allowed values: 'eui64', 'random', fixed value like '::1' " ..
|
||||
"or '::1:2'. When IPv6 prefix (like 'a:b:c:d::') is received from a " ..
|
||||
"delegating server, use the suffix (like '::1') to form the IPv6 address " ..
|
||||
"('a:b:c:d::1') for the interface."))
|
||||
ip6ifaceid.datatype = "ip6hostid"
|
||||
ip6ifaceid.placeholder = "::1"
|
||||
ip6ifaceid.rmempty = true
|
||||
|
||||
end
|
||||
|
||||
|
||||
luci.tools.proto.opt_macaddr(section, ifc, translate("Override MAC address"))
|
||||
|
||||
|
||||
mtu = section:taboption("advanced", Value, "mtu", translate("Override MTU"))
|
||||
mtu.placeholder = "1500"
|
||||
mtu.datatype = "max(9200)"
|
||||
|
||||
|
||||
metric = section:taboption("advanced", Value, "metric",
|
||||
translate("Use gateway metric"))
|
||||
|
||||
metric.default = "1"
|
||||
metric.datatype = "uinteger"
|
||||
|
||||
local nw = require "luci.model.network".init()
|
||||
for _, network in ipairs(nw:get_networks()) do
|
||||
if network:proto() == "static" and network:type() == "macvlan" and tonumber(network:metric()) >= tonumber(metric.default) then
|
||||
metric.default = network:metric() + 1
|
||||
end
|
||||
end
|
|
@ -1,568 +0,0 @@
|
|||
-- Copyright 2009 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local type, pairs, ipairs, table, luci, math
|
||||
= type, pairs, ipairs, table, luci, math
|
||||
|
||||
local tpl = require "luci.template.parser"
|
||||
local utl = require "luci.util"
|
||||
local uci = require "luci.model.uci"
|
||||
|
||||
module "luci.model.firewall"
|
||||
|
||||
|
||||
local uci_r, uci_s
|
||||
|
||||
function _valid_id(x)
|
||||
return (x and #x > 0 and x:match("^[a-zA-Z0-9_]+$"))
|
||||
end
|
||||
|
||||
function _get(c, s, o)
|
||||
return uci_r:get(c, s, o)
|
||||
end
|
||||
|
||||
function _set(c, s, o, v)
|
||||
if v ~= nil then
|
||||
if type(v) == "boolean" then v = v and "1" or "0" end
|
||||
return uci_r:set(c, s, o, v)
|
||||
else
|
||||
return uci_r:delete(c, s, o)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function init(cursor)
|
||||
uci_r = cursor or uci_r or uci.cursor()
|
||||
uci_s = uci_r:substate()
|
||||
|
||||
return _M
|
||||
end
|
||||
|
||||
function save(self, ...)
|
||||
uci_r:save(...)
|
||||
uci_r:load(...)
|
||||
end
|
||||
|
||||
function commit(self, ...)
|
||||
uci_r:commit(...)
|
||||
uci_r:load(...)
|
||||
end
|
||||
|
||||
function get_defaults()
|
||||
return defaults()
|
||||
end
|
||||
|
||||
function new_zone(self)
|
||||
local name = "newzone"
|
||||
local count = 1
|
||||
|
||||
while self:get_zone(name) do
|
||||
count = count + 1
|
||||
name = "newzone%d" % count
|
||||
end
|
||||
|
||||
return self:add_zone(name)
|
||||
end
|
||||
|
||||
function add_zone(self, n)
|
||||
if _valid_id(n) and not self:get_zone(n) then
|
||||
local d = defaults()
|
||||
local z = uci_r:section("firewall", "zone", nil, {
|
||||
name = n,
|
||||
network = " ",
|
||||
input = d:input() or "DROP",
|
||||
forward = d:forward() or "DROP",
|
||||
output = d:output() or "DROP"
|
||||
})
|
||||
|
||||
return z and zone(z)
|
||||
end
|
||||
end
|
||||
|
||||
function get_zone(self, n)
|
||||
if uci_r:get("firewall", n) == "zone" then
|
||||
return zone(n)
|
||||
else
|
||||
local z
|
||||
uci_r:foreach("firewall", "zone",
|
||||
function(s)
|
||||
if n and s.name == n then
|
||||
z = s['.name']
|
||||
return false
|
||||
end
|
||||
end)
|
||||
return z and zone(z)
|
||||
end
|
||||
end
|
||||
|
||||
function get_zones(self)
|
||||
local zones = { }
|
||||
local znl = { }
|
||||
|
||||
uci_r:foreach("firewall", "zone",
|
||||
function(s)
|
||||
if s.name then
|
||||
znl[s.name] = zone(s['.name'])
|
||||
end
|
||||
end)
|
||||
|
||||
local z
|
||||
for z in utl.kspairs(znl) do
|
||||
zones[#zones+1] = znl[z]
|
||||
end
|
||||
|
||||
return zones
|
||||
end
|
||||
|
||||
function get_zone_by_network(self, net)
|
||||
local z
|
||||
|
||||
uci_r:foreach("firewall", "zone",
|
||||
function(s)
|
||||
if s.name and net then
|
||||
local n
|
||||
for n in utl.imatch(s.network or s.name) do
|
||||
if n == net then
|
||||
z = s['.name']
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
return z and zone(z)
|
||||
end
|
||||
|
||||
function del_zone(self, n)
|
||||
local r = false
|
||||
|
||||
if uci_r:get("firewall", n) == "zone" then
|
||||
local z = uci_r:get("firewall", n, "name")
|
||||
r = uci_r:delete("firewall", n)
|
||||
n = z
|
||||
else
|
||||
uci_r:foreach("firewall", "zone",
|
||||
function(s)
|
||||
if n and s.name == n then
|
||||
r = uci_r:delete("firewall", s['.name'])
|
||||
return false
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
if r then
|
||||
uci_r:foreach("firewall", "rule",
|
||||
function(s)
|
||||
if s.src == n or s.dest == n then
|
||||
uci_r:delete("firewall", s['.name'])
|
||||
end
|
||||
end)
|
||||
|
||||
uci_r:foreach("firewall", "redirect",
|
||||
function(s)
|
||||
if s.src == n or s.dest == n then
|
||||
uci_r:delete("firewall", s['.name'])
|
||||
end
|
||||
end)
|
||||
|
||||
uci_r:foreach("firewall", "forwarding",
|
||||
function(s)
|
||||
if s.src == n or s.dest == n then
|
||||
uci_r:delete("firewall", s['.name'])
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
return r
|
||||
end
|
||||
|
||||
function rename_zone(self, old, new)
|
||||
local r = false
|
||||
|
||||
if _valid_id(new) and not self:get_zone(new) then
|
||||
uci_r:foreach("firewall", "zone",
|
||||
function(s)
|
||||
if old and s.name == old then
|
||||
if not s.network then
|
||||
uci_r:set("firewall", s['.name'], "network", old)
|
||||
end
|
||||
uci_r:set("firewall", s['.name'], "name", new)
|
||||
r = true
|
||||
return false
|
||||
end
|
||||
end)
|
||||
|
||||
if r then
|
||||
uci_r:foreach("firewall", "rule",
|
||||
function(s)
|
||||
if s.src == old then
|
||||
uci_r:set("firewall", s['.name'], "src", new)
|
||||
end
|
||||
if s.dest == old then
|
||||
uci_r:set("firewall", s['.name'], "dest", new)
|
||||
end
|
||||
end)
|
||||
|
||||
uci_r:foreach("firewall", "redirect",
|
||||
function(s)
|
||||
if s.src == old then
|
||||
uci_r:set("firewall", s['.name'], "src", new)
|
||||
end
|
||||
if s.dest == old then
|
||||
uci_r:set("firewall", s['.name'], "dest", new)
|
||||
end
|
||||
end)
|
||||
|
||||
uci_r:foreach("firewall", "forwarding",
|
||||
function(s)
|
||||
if s.src == old then
|
||||
uci_r:set("firewall", s['.name'], "src", new)
|
||||
end
|
||||
if s.dest == old then
|
||||
uci_r:set("firewall", s['.name'], "dest", new)
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
return r
|
||||
end
|
||||
|
||||
function del_network(self, net)
|
||||
local z
|
||||
if net then
|
||||
for _, z in ipairs(self:get_zones()) do
|
||||
z:del_network(net)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
defaults = utl.class()
|
||||
function defaults.__init__(self)
|
||||
uci_r:foreach("firewall", "defaults",
|
||||
function(s)
|
||||
self.sid = s['.name']
|
||||
return false
|
||||
end)
|
||||
|
||||
self.sid = self.sid or uci_r:section("firewall", "defaults", nil, { })
|
||||
end
|
||||
|
||||
function defaults.get(self, opt)
|
||||
return _get("firewall", self.sid, opt)
|
||||
end
|
||||
|
||||
function defaults.set(self, opt, val)
|
||||
return _set("firewall", self.sid, opt, val)
|
||||
end
|
||||
|
||||
function defaults.syn_flood(self)
|
||||
return (self:get("syn_flood") == "1")
|
||||
end
|
||||
|
||||
function defaults.drop_invalid(self)
|
||||
return (self:get("drop_invalid") == "1")
|
||||
end
|
||||
|
||||
function defaults.input(self)
|
||||
return self:get("input") or "DROP"
|
||||
end
|
||||
|
||||
function defaults.forward(self)
|
||||
return self:get("forward") or "DROP"
|
||||
end
|
||||
|
||||
function defaults.output(self)
|
||||
return self:get("output") or "DROP"
|
||||
end
|
||||
|
||||
|
||||
zone = utl.class()
|
||||
function zone.__init__(self, z)
|
||||
if uci_r:get("firewall", z) == "zone" then
|
||||
self.sid = z
|
||||
self.data = uci_r:get_all("firewall", z)
|
||||
else
|
||||
uci_r:foreach("firewall", "zone",
|
||||
function(s)
|
||||
if s.name == z then
|
||||
self.sid = s['.name']
|
||||
self.data = s
|
||||
return false
|
||||
end
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function zone.get(self, opt)
|
||||
return _get("firewall", self.sid, opt)
|
||||
end
|
||||
|
||||
function zone.set(self, opt, val)
|
||||
return _set("firewall", self.sid, opt, val)
|
||||
end
|
||||
|
||||
function zone.masq(self)
|
||||
return (self:get("masq") == "1")
|
||||
end
|
||||
|
||||
function zone.name(self)
|
||||
return self:get("name")
|
||||
end
|
||||
|
||||
function zone.network(self)
|
||||
return self:get("network")
|
||||
end
|
||||
|
||||
function zone.input(self)
|
||||
return self:get("input") or defaults():input() or "DROP"
|
||||
end
|
||||
|
||||
function zone.forward(self)
|
||||
return self:get("forward") or defaults():forward() or "DROP"
|
||||
end
|
||||
|
||||
function zone.output(self)
|
||||
return self:get("output") or defaults():output() or "DROP"
|
||||
end
|
||||
|
||||
function zone.add_network(self, net)
|
||||
if uci_r:get("network", net) == "interface" then
|
||||
local nets = { }
|
||||
|
||||
local n
|
||||
for n in utl.imatch(self:get("network") or self:get("name")) do
|
||||
if n ~= net then
|
||||
nets[#nets+1] = n
|
||||
end
|
||||
end
|
||||
|
||||
nets[#nets+1] = net
|
||||
|
||||
_M:del_network(net)
|
||||
self:set("network", table.concat(nets, " "))
|
||||
end
|
||||
end
|
||||
|
||||
function zone.del_network(self, net)
|
||||
local nets = { }
|
||||
|
||||
local n
|
||||
for n in utl.imatch(self:get("network") or self:get("name")) do
|
||||
if n ~= net then
|
||||
nets[#nets+1] = n
|
||||
end
|
||||
end
|
||||
|
||||
if #nets > 0 then
|
||||
self:set("network", table.concat(nets, " "))
|
||||
else
|
||||
self:set("network", " ")
|
||||
end
|
||||
end
|
||||
|
||||
function zone.get_networks(self)
|
||||
local nets = { }
|
||||
|
||||
local n
|
||||
for n in utl.imatch(self:get("network") or self:get("name")) do
|
||||
nets[#nets+1] = n
|
||||
end
|
||||
|
||||
return nets
|
||||
end
|
||||
|
||||
function zone.clear_networks(self)
|
||||
self:set("network", " ")
|
||||
end
|
||||
|
||||
function zone.get_forwardings_by(self, what)
|
||||
local name = self:name()
|
||||
local forwards = { }
|
||||
|
||||
uci_r:foreach("firewall", "forwarding",
|
||||
function(s)
|
||||
if s.src and s.dest and s[what] == name then
|
||||
forwards[#forwards+1] = forwarding(s['.name'])
|
||||
end
|
||||
end)
|
||||
|
||||
return forwards
|
||||
end
|
||||
|
||||
function zone.add_forwarding_to(self, dest)
|
||||
local exist, forward
|
||||
|
||||
for _, forward in ipairs(self:get_forwardings_by('src')) do
|
||||
if forward:dest() == dest then
|
||||
exist = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not exist and dest ~= self:name() and _valid_id(dest) then
|
||||
local s = uci_r:section("firewall", "forwarding", nil, {
|
||||
src = self:name(),
|
||||
dest = dest
|
||||
})
|
||||
|
||||
return s and forwarding(s)
|
||||
end
|
||||
end
|
||||
|
||||
function zone.add_forwarding_from(self, src)
|
||||
local exist, forward
|
||||
|
||||
for _, forward in ipairs(self:get_forwardings_by('dest')) do
|
||||
if forward:src() == src then
|
||||
exist = true
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not exist and src ~= self:name() and _valid_id(src) then
|
||||
local s = uci_r:section("firewall", "forwarding", nil, {
|
||||
src = src,
|
||||
dest = self:name()
|
||||
})
|
||||
|
||||
return s and forwarding(s)
|
||||
end
|
||||
end
|
||||
|
||||
function zone.del_forwardings_by(self, what)
|
||||
local name = self:name()
|
||||
|
||||
uci_r:delete_all("firewall", "forwarding",
|
||||
function(s)
|
||||
return (s.src and s.dest and s[what] == name)
|
||||
end)
|
||||
end
|
||||
|
||||
function zone.add_redirect(self, options)
|
||||
options = options or { }
|
||||
options.src = self:name()
|
||||
|
||||
local s = uci_r:section("firewall", "redirect", nil, options)
|
||||
return s and redirect(s)
|
||||
end
|
||||
|
||||
function zone.add_rule(self, options)
|
||||
options = options or { }
|
||||
options.src = self:name()
|
||||
|
||||
local s = uci_r:section("firewall", "rule", nil, options)
|
||||
return s and rule(s)
|
||||
end
|
||||
|
||||
function zone.get_color(self)
|
||||
if self and self:name() == "lan" then
|
||||
return "#90f090"
|
||||
elseif self and self:name() == "wan" then
|
||||
return "#f09090"
|
||||
elseif self then
|
||||
math.randomseed(tpl.hash(self:name()))
|
||||
|
||||
local r = math.random(128)
|
||||
local g = math.random(128)
|
||||
local min = 0
|
||||
local max = 128
|
||||
|
||||
if ( r + g ) < 128 then
|
||||
min = 128 - r - g
|
||||
else
|
||||
max = 255 - r - g
|
||||
end
|
||||
|
||||
local b = min + math.floor( math.random() * ( max - min ) )
|
||||
|
||||
return "#%02x%02x%02x" % { 0xFF - r, 0xFF - g, 0xFF - b }
|
||||
else
|
||||
return "#eeeeee"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
forwarding = utl.class()
|
||||
function forwarding.__init__(self, f)
|
||||
self.sid = f
|
||||
end
|
||||
|
||||
function forwarding.src(self)
|
||||
return uci_r:get("firewall", self.sid, "src")
|
||||
end
|
||||
|
||||
function forwarding.dest(self)
|
||||
return uci_r:get("firewall", self.sid, "dest")
|
||||
end
|
||||
|
||||
function forwarding.src_zone(self)
|
||||
local z = zone(self:src())
|
||||
return z.sid and z
|
||||
end
|
||||
|
||||
function forwarding.dest_zone(self)
|
||||
local z = zone(self:dest())
|
||||
return z.sid and z
|
||||
end
|
||||
|
||||
|
||||
rule = utl.class()
|
||||
function rule.__init__(self, f)
|
||||
self.sid = f
|
||||
end
|
||||
|
||||
function rule.get(self, opt)
|
||||
return _get("firewall", self.sid, opt)
|
||||
end
|
||||
|
||||
function rule.set(self, opt, val)
|
||||
return _set("firewall", self.sid, opt, val)
|
||||
end
|
||||
|
||||
function rule.src(self)
|
||||
return uci_r:get("firewall", self.sid, "src")
|
||||
end
|
||||
|
||||
function rule.dest(self)
|
||||
return uci_r:get("firewall", self.sid, "dest")
|
||||
end
|
||||
|
||||
function rule.src_zone(self)
|
||||
return zone(self:src())
|
||||
end
|
||||
|
||||
function rule.dest_zone(self)
|
||||
return zone(self:dest())
|
||||
end
|
||||
|
||||
|
||||
redirect = utl.class()
|
||||
function redirect.__init__(self, f)
|
||||
self.sid = f
|
||||
end
|
||||
|
||||
function redirect.get(self, opt)
|
||||
return _get("firewall", self.sid, opt)
|
||||
end
|
||||
|
||||
function redirect.set(self, opt, val)
|
||||
return _set("firewall", self.sid, opt, val)
|
||||
end
|
||||
|
||||
function redirect.src(self)
|
||||
return uci_r:get("firewall", self.sid, "src")
|
||||
end
|
||||
|
||||
function redirect.dest(self)
|
||||
return uci_r:get("firewall", self.sid, "dest")
|
||||
end
|
||||
|
||||
function redirect.src_zone(self)
|
||||
return zone(self:src())
|
||||
end
|
||||
|
||||
function redirect.dest_zone(self)
|
||||
return zone(self:dest())
|
||||
end
|
|
@ -1,247 +0,0 @@
|
|||
-- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local os = require "os"
|
||||
local io = require "io"
|
||||
local fs = require "nixio.fs"
|
||||
local util = require "luci.util"
|
||||
|
||||
local type = type
|
||||
local pairs = pairs
|
||||
local error = error
|
||||
local table = table
|
||||
|
||||
local ipkg = "opkg --force-removal-of-dependent-packages --force-overwrite --nocase"
|
||||
local icfg = "/etc/opkg.conf"
|
||||
|
||||
module "luci.model.ipkg"
|
||||
|
||||
|
||||
-- Internal action function
|
||||
local function _action(cmd, ...)
|
||||
local cmdline = { ipkg, cmd }
|
||||
|
||||
local k, v
|
||||
for k, v in pairs({...}) do
|
||||
cmdline[#cmdline+1] = util.shellquote(v)
|
||||
end
|
||||
|
||||
local c = "%s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" % table.concat(cmdline, " ")
|
||||
local r = os.execute(c)
|
||||
local e = fs.readfile("/tmp/opkg.stderr")
|
||||
local o = fs.readfile("/tmp/opkg.stdout")
|
||||
|
||||
fs.unlink("/tmp/opkg.stderr")
|
||||
fs.unlink("/tmp/opkg.stdout")
|
||||
|
||||
return r, o or "", e or ""
|
||||
end
|
||||
|
||||
-- Internal parser function
|
||||
local function _parselist(rawdata)
|
||||
if type(rawdata) ~= "function" then
|
||||
error("OPKG: Invalid rawdata given")
|
||||
end
|
||||
|
||||
local data = {}
|
||||
local c = {}
|
||||
local l = nil
|
||||
|
||||
for line in rawdata do
|
||||
if line:sub(1, 1) ~= " " then
|
||||
local key, val = line:match("(.-): ?(.*)%s*")
|
||||
|
||||
if key and val then
|
||||
if key == "Package" then
|
||||
c = {Package = val}
|
||||
data[val] = c
|
||||
elseif key == "Status" then
|
||||
c.Status = {}
|
||||
for j in val:gmatch("([^ ]+)") do
|
||||
c.Status[j] = true
|
||||
end
|
||||
else
|
||||
c[key] = val
|
||||
end
|
||||
l = key
|
||||
end
|
||||
else
|
||||
-- Multi-line field
|
||||
c[l] = c[l] .. "\n" .. line
|
||||
end
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
-- Internal lookup function
|
||||
local function _lookup(cmd, pkg)
|
||||
local cmdline = { ipkg, cmd }
|
||||
if pkg then
|
||||
cmdline[#cmdline+1] = util.shellquote(pkg)
|
||||
end
|
||||
|
||||
-- OPKG sometimes kills the whole machine because it sucks
|
||||
-- Therefore we have to use a sucky approach too and use
|
||||
-- tmpfiles instead of directly reading the output
|
||||
local tmpfile = os.tmpname()
|
||||
os.execute("%s >%s 2>/dev/null" %{ table.concat(cmdline, " "), tmpfile })
|
||||
|
||||
local data = _parselist(io.lines(tmpfile))
|
||||
os.remove(tmpfile)
|
||||
return data
|
||||
end
|
||||
|
||||
|
||||
function info(pkg)
|
||||
return _lookup("info", pkg)
|
||||
end
|
||||
|
||||
function status(pkg)
|
||||
return _lookup("status", pkg)
|
||||
end
|
||||
|
||||
function install(...)
|
||||
return _action("install", ...)
|
||||
end
|
||||
|
||||
function installed(pkg)
|
||||
local p = status(pkg)[pkg]
|
||||
return (p and p.Status and p.Status.installed)
|
||||
end
|
||||
|
||||
function remove(...)
|
||||
return _action("remove", ...)
|
||||
end
|
||||
|
||||
function update()
|
||||
return _action("update")
|
||||
end
|
||||
|
||||
function upgrade()
|
||||
return _action("upgrade")
|
||||
end
|
||||
|
||||
-- List helper
|
||||
local function _list(action, pat, cb)
|
||||
local cmdline = { ipkg, action }
|
||||
if pat then
|
||||
cmdline[#cmdline+1] = util.shellquote(pat)
|
||||
end
|
||||
|
||||
local fd = io.popen(table.concat(cmdline, " "))
|
||||
if fd then
|
||||
local name, version, sz, desc
|
||||
while true do
|
||||
local line = fd:read("*l")
|
||||
if not line then break end
|
||||
|
||||
name, version, sz, desc = line:match("^(.-) %- (.-) %- (.-) %- (.+)")
|
||||
|
||||
if not name then
|
||||
name, version, sz = line:match("^(.-) %- (.-) %- (.+)")
|
||||
desc = ""
|
||||
end
|
||||
|
||||
if name and version then
|
||||
if #version > 26 then
|
||||
version = version:sub(1,21) .. ".." .. version:sub(-3,-1)
|
||||
end
|
||||
|
||||
cb(name, version, sz, desc)
|
||||
end
|
||||
|
||||
name = nil
|
||||
version = nil
|
||||
sz = nil
|
||||
desc = nil
|
||||
end
|
||||
|
||||
fd:close()
|
||||
end
|
||||
end
|
||||
|
||||
function list_all(pat, cb)
|
||||
_list("list --size", pat, cb)
|
||||
end
|
||||
|
||||
function list_installed(pat, cb)
|
||||
_list("list_installed --size", pat, cb)
|
||||
end
|
||||
|
||||
function find(pat, cb)
|
||||
_list("find --size", pat, cb)
|
||||
end
|
||||
|
||||
|
||||
function overlay_root()
|
||||
local od = "/"
|
||||
local fd = io.open(icfg, "r")
|
||||
|
||||
if fd then
|
||||
local ln
|
||||
|
||||
repeat
|
||||
ln = fd:read("*l")
|
||||
if ln and ln:match("^%s*option%s+overlay_root%s+") then
|
||||
od = ln:match("^%s*option%s+overlay_root%s+(%S+)")
|
||||
|
||||
local s = fs.stat(od)
|
||||
if not s or s.type ~= "dir" then
|
||||
od = "/"
|
||||
end
|
||||
|
||||
break
|
||||
end
|
||||
until not ln
|
||||
|
||||
fd:close()
|
||||
end
|
||||
|
||||
return od
|
||||
end
|
||||
|
||||
function compare_versions(ver1, comp, ver2)
|
||||
if not ver1 or not ver2
|
||||
or not comp or not (#comp > 0) then
|
||||
error("Invalid parameters")
|
||||
return nil
|
||||
end
|
||||
-- correct compare string
|
||||
if comp == "<>" or comp == "><" or comp == "!=" or comp == "~=" then comp = "~="
|
||||
elseif comp == "<=" or comp == "<" or comp == "=<" then comp = "<="
|
||||
elseif comp == ">=" or comp == ">" or comp == "=>" then comp = ">="
|
||||
elseif comp == "=" or comp == "==" then comp = "=="
|
||||
elseif comp == "<<" then comp = "<"
|
||||
elseif comp == ">>" then comp = ">"
|
||||
else
|
||||
error("Invalid compare string")
|
||||
return nil
|
||||
end
|
||||
|
||||
local av1 = util.split(ver1, "[%.%-]", nil, true)
|
||||
local av2 = util.split(ver2, "[%.%-]", nil, true)
|
||||
|
||||
local max = table.getn(av1)
|
||||
if (table.getn(av1) < table.getn(av2)) then
|
||||
max = table.getn(av2)
|
||||
end
|
||||
|
||||
for i = 1, max, 1 do
|
||||
local s1 = av1[i] or ""
|
||||
local s2 = av2[i] or ""
|
||||
|
||||
-- first "not equal" found return true
|
||||
if comp == "~=" and (s1 ~= s2) then return true end
|
||||
-- first "lower" found return true
|
||||
if (comp == "<" or comp == "<=") and (s1 < s2) then return true end
|
||||
-- first "greater" found return true
|
||||
if (comp == ">" or comp == ">=") and (s1 > s2) then return true end
|
||||
-- not equal then return false
|
||||
if (s1 ~= s2) then return false end
|
||||
end
|
||||
|
||||
-- all equal and not compare greater or lower then true
|
||||
return not (comp == "<" or comp == ">")
|
||||
end
|
|
@ -1,125 +0,0 @@
|
|||
---[[
|
||||
LuCI OPKG call abstraction library
|
||||
]]
|
||||
module "luci.model.ipkg"
|
||||
|
||||
---[[
|
||||
Return information about installed and available packages.
|
||||
|
||||
@class function
|
||||
@name info
|
||||
@param pkg Limit output to a (set of) packages
|
||||
@return Table containing package information
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return the package status of one or more packages.
|
||||
|
||||
@class function
|
||||
@name status
|
||||
@param pkg Limit output to a (set of) packages
|
||||
@return Table containing package status information
|
||||
]]
|
||||
|
||||
---[[
|
||||
Install one or more packages.
|
||||
|
||||
@class function
|
||||
@name install
|
||||
@param ... List of packages to install
|
||||
@return Boolean indicating the status of the action
|
||||
@return OPKG return code, STDOUT and STDERR
|
||||
]]
|
||||
|
||||
---[[
|
||||
Determine whether a given package is installed.
|
||||
|
||||
@class function
|
||||
@name installed
|
||||
@param pkg Package
|
||||
@return Boolean
|
||||
]]
|
||||
|
||||
---[[
|
||||
Remove one or more packages.
|
||||
|
||||
@class function
|
||||
@name remove
|
||||
@param ... List of packages to install
|
||||
@return Boolean indicating the status of the action
|
||||
@return OPKG return code, STDOUT and STDERR
|
||||
]]
|
||||
|
||||
---[[
|
||||
Update package lists.
|
||||
|
||||
@class function
|
||||
@name update
|
||||
@return Boolean indicating the status of the action
|
||||
@return OPKG return code, STDOUT and STDERR
|
||||
]]
|
||||
|
||||
---[[
|
||||
Upgrades all installed packages.
|
||||
|
||||
@class function
|
||||
@name upgrade
|
||||
@return Boolean indicating the status of the action
|
||||
@return OPKG return code, STDOUT and STDERR
|
||||
]]
|
||||
|
||||
---[[
|
||||
List all packages known to opkg.
|
||||
|
||||
@class function
|
||||
@name list_all
|
||||
@param pat Only find packages matching this pattern, nil lists all packages
|
||||
@param cb Callback function invoked for each package, receives name, version and description as arguments
|
||||
@return nothing
|
||||
]]
|
||||
|
||||
---[[
|
||||
List installed packages.
|
||||
|
||||
@class function
|
||||
@name list_installed
|
||||
@param pat Only find packages matching this pattern, nil lists all packages
|
||||
@param cb Callback function invoked for each package, receives name, version and description as arguments
|
||||
@return nothing
|
||||
]]
|
||||
|
||||
---[[
|
||||
Find packages that match the given pattern.
|
||||
|
||||
@class function
|
||||
@name find
|
||||
@param pat Find packages whose names or descriptions match this pattern, nil results in zero results
|
||||
@param cb Callback function invoked for each patckage, receives name, version and description as arguments
|
||||
@return nothing
|
||||
]]
|
||||
|
||||
---[[
|
||||
Determines the overlay root used by opkg.
|
||||
|
||||
@class function
|
||||
@name overlay_root
|
||||
@return String containing the directory path of the overlay root.
|
||||
]]
|
||||
|
||||
---[[
|
||||
lua version of opkg compare-versions
|
||||
|
||||
@class function
|
||||
@name compare_versions
|
||||
@param ver1 string version 1
|
||||
@param ver2 string version 2
|
||||
@param comp string compare versions using
|
||||
"<=" or "<" lower-equal
|
||||
">" or ">=" greater-equal
|
||||
"=" equal
|
||||
"<<" lower
|
||||
">>" greater
|
||||
"~=" not equal
|
||||
@return Boolean indicating the status of the compare
|
||||
]]
|
||||
|
|
@ -1,534 +0,0 @@
|
|||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local os = require "os"
|
||||
local util = require "luci.util"
|
||||
local table = require "table"
|
||||
|
||||
|
||||
local setmetatable, rawget, rawset = setmetatable, rawget, rawset
|
||||
local require, getmetatable, assert = require, getmetatable, assert
|
||||
local error, pairs, ipairs, select = error, pairs, ipairs, select
|
||||
local type, tostring, tonumber, unpack = type, tostring, tonumber, unpack
|
||||
|
||||
-- The typical workflow for UCI is: Get a cursor instance from the
|
||||
-- cursor factory, modify data (via Cursor.add, Cursor.delete, etc.),
|
||||
-- save the changes to the staging area via Cursor.save and finally
|
||||
-- Cursor.commit the data to the actual config files.
|
||||
-- LuCI then needs to Cursor.apply the changes so deamons etc. are
|
||||
-- reloaded.
|
||||
module "luci.model.uci"
|
||||
|
||||
local ERRSTR = {
|
||||
"Invalid command",
|
||||
"Invalid argument",
|
||||
"Method not found",
|
||||
"Entry not found",
|
||||
"No data",
|
||||
"Permission denied",
|
||||
"Timeout",
|
||||
"Not supported",
|
||||
"Unknown error",
|
||||
"Connection failed"
|
||||
}
|
||||
|
||||
local session_id = nil
|
||||
|
||||
local function call(cmd, args)
|
||||
if type(args) == "table" and session_id then
|
||||
args.ubus_rpc_session = session_id
|
||||
end
|
||||
return util.ubus("uci", cmd, args)
|
||||
end
|
||||
|
||||
|
||||
function cursor()
|
||||
return _M
|
||||
end
|
||||
|
||||
function cursor_state()
|
||||
return _M
|
||||
end
|
||||
|
||||
function substate(self)
|
||||
return self
|
||||
end
|
||||
|
||||
|
||||
function get_confdir(self)
|
||||
return "/etc/config"
|
||||
end
|
||||
|
||||
function get_savedir(self)
|
||||
return "/tmp/.uci"
|
||||
end
|
||||
|
||||
function get_session_id(self)
|
||||
return session_id
|
||||
end
|
||||
|
||||
function set_confdir(self, directory)
|
||||
return false
|
||||
end
|
||||
|
||||
function set_savedir(self, directory)
|
||||
return false
|
||||
end
|
||||
|
||||
function set_session_id(self, id)
|
||||
session_id = id
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function load(self, config)
|
||||
return true
|
||||
end
|
||||
|
||||
function save(self, config)
|
||||
return true
|
||||
end
|
||||
|
||||
function unload(self, config)
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function changes(self, config)
|
||||
local rv = call("changes", { config = config })
|
||||
local res = {}
|
||||
|
||||
if type(rv) == "table" and type(rv.changes) == "table" then
|
||||
local package, changes
|
||||
for package, changes in pairs(rv.changes) do
|
||||
res[package] = {}
|
||||
|
||||
local _, change
|
||||
for _, change in ipairs(changes) do
|
||||
local operation, section, option, value = unpack(change)
|
||||
if option and operation ~= "add" then
|
||||
res[package][section] = res[package][section] or { }
|
||||
|
||||
if operation == "list-add" then
|
||||
local v = res[package][section][option]
|
||||
if type(v) == "table" then
|
||||
v[#v+1] = value or ""
|
||||
elseif v ~= nil then
|
||||
res[package][section][option] = { v, value }
|
||||
else
|
||||
res[package][section][option] = { value }
|
||||
end
|
||||
else
|
||||
res[package][section][option] = value or ""
|
||||
end
|
||||
else
|
||||
res[package][section] = res[package][section] or {}
|
||||
res[package][section][".type"] = option or ""
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return res
|
||||
end
|
||||
|
||||
|
||||
function revert(self, config)
|
||||
local _, err = call("revert", { config = config })
|
||||
return (err == nil), ERRSTR[err]
|
||||
end
|
||||
|
||||
function commit(self, config)
|
||||
local _, err = call("commit", { config = config })
|
||||
return (err == nil), ERRSTR[err]
|
||||
end
|
||||
|
||||
function apply(self, rollback)
|
||||
local _, err
|
||||
|
||||
if rollback then
|
||||
local sys = require "luci.sys"
|
||||
local conf = require "luci.config"
|
||||
local timeout = tonumber(conf and conf.apply and conf.apply.rollback or 30) or 0
|
||||
|
||||
_, err = call("apply", {
|
||||
timeout = (timeout > 30) and timeout or 30,
|
||||
rollback = true
|
||||
})
|
||||
|
||||
if not err then
|
||||
local now = os.time()
|
||||
local token = sys.uniqueid(16)
|
||||
|
||||
util.ubus("session", "set", {
|
||||
ubus_rpc_session = "00000000000000000000000000000000",
|
||||
values = {
|
||||
rollback = {
|
||||
token = token,
|
||||
session = session_id,
|
||||
timeout = now + timeout
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
return token
|
||||
end
|
||||
else
|
||||
_, err = call("changes", {})
|
||||
|
||||
if not err then
|
||||
if type(_) == "table" and type(_.changes) == "table" then
|
||||
local k, v
|
||||
for k, v in pairs(_.changes) do
|
||||
_, err = call("commit", { config = k })
|
||||
if err then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not err then
|
||||
_, err = call("apply", { rollback = false })
|
||||
end
|
||||
end
|
||||
|
||||
return (err == nil), ERRSTR[err]
|
||||
end
|
||||
|
||||
function confirm(self, token)
|
||||
local is_pending, time_remaining, rollback_sid, rollback_token = self:rollback_pending()
|
||||
|
||||
if is_pending then
|
||||
if token ~= rollback_token then
|
||||
return false, "Permission denied"
|
||||
end
|
||||
|
||||
local _, err = util.ubus("uci", "confirm", {
|
||||
ubus_rpc_session = rollback_sid
|
||||
})
|
||||
|
||||
if not err then
|
||||
util.ubus("session", "set", {
|
||||
ubus_rpc_session = "00000000000000000000000000000000",
|
||||
values = { rollback = {} }
|
||||
})
|
||||
end
|
||||
|
||||
return (err == nil), ERRSTR[err]
|
||||
end
|
||||
|
||||
return false, "No data"
|
||||
end
|
||||
|
||||
function rollback(self)
|
||||
local is_pending, time_remaining, rollback_sid = self:rollback_pending()
|
||||
|
||||
if is_pending then
|
||||
local _, err = util.ubus("uci", "rollback", {
|
||||
ubus_rpc_session = rollback_sid
|
||||
})
|
||||
|
||||
if not err then
|
||||
util.ubus("session", "set", {
|
||||
ubus_rpc_session = "00000000000000000000000000000000",
|
||||
values = { rollback = {} }
|
||||
})
|
||||
end
|
||||
|
||||
return (err == nil), ERRSTR[err]
|
||||
end
|
||||
|
||||
return false, "No data"
|
||||
end
|
||||
|
||||
function rollback_pending(self)
|
||||
local rv, err = util.ubus("session", "get", {
|
||||
ubus_rpc_session = "00000000000000000000000000000000",
|
||||
keys = { "rollback" }
|
||||
})
|
||||
|
||||
local now = os.time()
|
||||
|
||||
if type(rv) == "table" and
|
||||
type(rv.values) == "table" and
|
||||
type(rv.values.rollback) == "table" and
|
||||
type(rv.values.rollback.token) == "string" and
|
||||
type(rv.values.rollback.session) == "string" and
|
||||
type(rv.values.rollback.timeout) == "number" and
|
||||
rv.values.rollback.timeout > now
|
||||
then
|
||||
return true,
|
||||
rv.values.rollback.timeout - now,
|
||||
rv.values.rollback.session,
|
||||
rv.values.rollback.token
|
||||
end
|
||||
|
||||
return false, ERRSTR[err]
|
||||
end
|
||||
|
||||
|
||||
function foreach(self, config, stype, callback)
|
||||
if type(callback) == "function" then
|
||||
local rv, err = call("get", {
|
||||
config = config,
|
||||
type = stype
|
||||
})
|
||||
|
||||
if type(rv) == "table" and type(rv.values) == "table" then
|
||||
local sections = { }
|
||||
local res = false
|
||||
local index = 1
|
||||
|
||||
local _, section
|
||||
for _, section in pairs(rv.values) do
|
||||
section[".index"] = section[".index"] or index
|
||||
sections[index] = section
|
||||
index = index + 1
|
||||
end
|
||||
|
||||
table.sort(sections, function(a, b)
|
||||
return a[".index"] < b[".index"]
|
||||
end)
|
||||
|
||||
for _, section in ipairs(sections) do
|
||||
local continue = callback(section)
|
||||
res = true
|
||||
if continue == false then
|
||||
break
|
||||
end
|
||||
end
|
||||
return res
|
||||
else
|
||||
return false, ERRSTR[err] or "No data"
|
||||
end
|
||||
else
|
||||
return false, "Invalid argument"
|
||||
end
|
||||
end
|
||||
|
||||
local function _get(self, operation, config, section, option)
|
||||
if section == nil then
|
||||
return nil
|
||||
elseif type(option) == "string" and option:byte(1) ~= 46 then
|
||||
local rv, err = call(operation, {
|
||||
config = config,
|
||||
section = section,
|
||||
option = option
|
||||
})
|
||||
|
||||
if type(rv) == "table" then
|
||||
return rv.value or nil
|
||||
elseif err then
|
||||
return false, ERRSTR[err]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
elseif option == nil then
|
||||
local values = self:get_all(config, section)
|
||||
if values then
|
||||
return values[".type"], values[".name"]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
else
|
||||
return false, "Invalid argument"
|
||||
end
|
||||
end
|
||||
|
||||
function get(self, ...)
|
||||
return _get(self, "get", ...)
|
||||
end
|
||||
|
||||
function get_state(self, ...)
|
||||
return _get(self, "state", ...)
|
||||
end
|
||||
|
||||
function get_all(self, config, section)
|
||||
local rv, err = call("get", {
|
||||
config = config,
|
||||
section = section
|
||||
})
|
||||
|
||||
if type(rv) == "table" and type(rv.values) == "table" then
|
||||
return rv.values
|
||||
elseif err then
|
||||
return false, ERRSTR[err]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
function get_bool(self, ...)
|
||||
local val = self:get(...)
|
||||
return (val == "1" or val == "true" or val == "yes" or val == "on")
|
||||
end
|
||||
|
||||
function get_first(self, config, stype, option, default)
|
||||
local rv = default
|
||||
|
||||
self:foreach(config, stype, function(s)
|
||||
local val = not option and s[".name"] or s[option]
|
||||
|
||||
if type(default) == "number" then
|
||||
val = tonumber(val)
|
||||
elseif type(default) == "boolean" then
|
||||
val = (val == "1" or val == "true" or
|
||||
val == "yes" or val == "on")
|
||||
end
|
||||
|
||||
if val ~= nil then
|
||||
rv = val
|
||||
return false
|
||||
end
|
||||
end)
|
||||
|
||||
return rv
|
||||
end
|
||||
|
||||
function get_list(self, config, section, option)
|
||||
if config and section and option then
|
||||
local val = self:get(config, section, option)
|
||||
return (type(val) == "table" and val or { val })
|
||||
end
|
||||
return { }
|
||||
end
|
||||
|
||||
|
||||
function section(self, config, stype, name, values)
|
||||
local rv, err = call("add", {
|
||||
config = config,
|
||||
type = stype,
|
||||
name = name,
|
||||
values = values
|
||||
})
|
||||
|
||||
if type(rv) == "table" then
|
||||
return rv.section
|
||||
elseif err then
|
||||
return false, ERRSTR[err]
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function add(self, config, stype)
|
||||
return self:section(config, stype)
|
||||
end
|
||||
|
||||
function set(self, config, section, option, ...)
|
||||
if select('#', ...) == 0 then
|
||||
local sname, err = self:section(config, option, section)
|
||||
return (not not sname), err
|
||||
else
|
||||
local _, err = call("set", {
|
||||
config = config,
|
||||
section = section,
|
||||
values = { [option] = select(1, ...) }
|
||||
})
|
||||
return (err == nil), ERRSTR[err]
|
||||
end
|
||||
end
|
||||
|
||||
function set_list(self, config, section, option, value)
|
||||
if section == nil or option == nil then
|
||||
return false
|
||||
elseif value == nil or (type(value) == "table" and #value == 0) then
|
||||
return self:delete(config, section, option)
|
||||
elseif type(value) == "table" then
|
||||
return self:set(config, section, option, value)
|
||||
else
|
||||
return self:set(config, section, option, { value })
|
||||
end
|
||||
end
|
||||
|
||||
function tset(self, config, section, values)
|
||||
local _, err = call("set", {
|
||||
config = config,
|
||||
section = section,
|
||||
values = values
|
||||
})
|
||||
return (err == nil), ERRSTR[err]
|
||||
end
|
||||
|
||||
function reorder(self, config, section, index)
|
||||
local sections
|
||||
|
||||
if type(section) == "string" and type(index) == "number" then
|
||||
local pos = 0
|
||||
|
||||
sections = { }
|
||||
|
||||
self:foreach(config, nil, function(s)
|
||||
if pos == index then
|
||||
pos = pos + 1
|
||||
end
|
||||
|
||||
if s[".name"] ~= section then
|
||||
pos = pos + 1
|
||||
sections[pos] = s[".name"]
|
||||
else
|
||||
sections[index + 1] = section
|
||||
end
|
||||
end)
|
||||
elseif type(section) == "table" then
|
||||
sections = section
|
||||
else
|
||||
return false, "Invalid argument"
|
||||
end
|
||||
|
||||
local _, err = call("order", {
|
||||
config = config,
|
||||
sections = sections
|
||||
})
|
||||
|
||||
return (err == nil), ERRSTR[err]
|
||||
end
|
||||
|
||||
|
||||
function delete(self, config, section, option)
|
||||
local _, err = call("delete", {
|
||||
config = config,
|
||||
section = section,
|
||||
option = option
|
||||
})
|
||||
return (err == nil), ERRSTR[err]
|
||||
end
|
||||
|
||||
function delete_all(self, config, stype, comparator)
|
||||
local _, err
|
||||
if type(comparator) == "table" then
|
||||
_, err = call("delete", {
|
||||
config = config,
|
||||
type = stype,
|
||||
match = comparator
|
||||
})
|
||||
elseif type(comparator) == "function" then
|
||||
local rv = call("get", {
|
||||
config = config,
|
||||
type = stype
|
||||
})
|
||||
|
||||
if type(rv) == "table" and type(rv.values) == "table" then
|
||||
local sname, section
|
||||
for sname, section in pairs(rv.values) do
|
||||
if comparator(section) then
|
||||
_, err = call("delete", {
|
||||
config = config,
|
||||
section = sname
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif comparator == nil then
|
||||
_, err = call("delete", {
|
||||
config = config,
|
||||
type = stype
|
||||
})
|
||||
else
|
||||
return false, "Invalid argument"
|
||||
end
|
||||
|
||||
return (err == nil), ERRSTR[err]
|
||||
end
|
|
@ -1,369 +0,0 @@
|
|||
---[[
|
||||
LuCI UCI model library.
|
||||
|
||||
The typical workflow for UCI is: Get a cursor instance from the
|
||||
cursor factory, modify data (via Cursor.add, Cursor.delete, etc.),
|
||||
save the changes to the staging area via Cursor.save and finally
|
||||
Cursor.commit the data to the actual config files.
|
||||
LuCI then needs to Cursor.apply the changes so deamons etc. are
|
||||
reloaded.
|
||||
@cstyle instance
|
||||
]]
|
||||
module "luci.model.uci"
|
||||
|
||||
---[[
|
||||
Create a new UCI-Cursor.
|
||||
|
||||
@class function
|
||||
@name cursor
|
||||
@return UCI-Cursor
|
||||
]]
|
||||
|
||||
---[[
|
||||
Create a new Cursor initialized to the state directory.
|
||||
|
||||
@class function
|
||||
@name cursor_state
|
||||
@return UCI cursor
|
||||
]]
|
||||
|
||||
---[[
|
||||
Applies UCI configuration changes.
|
||||
|
||||
If the rollback parameter is set to true, the apply function will invoke the
|
||||
rollback mechanism which causes the configuration to be automatically reverted
|
||||
if no confirm() call occurs within a certain timeout.
|
||||
|
||||
The current default timeout is 30s and can be increased using the
|
||||
"luci.apply.timeout" uci configuration key.
|
||||
|
||||
@class function
|
||||
@name Cursor.apply
|
||||
@param rollback Enable rollback mechanism
|
||||
@return Boolean whether operation succeeded
|
||||
]]
|
||||
|
||||
---[[
|
||||
Confirms UCI apply process.
|
||||
|
||||
If a previous UCI apply with rollback has been invoked using apply(true),
|
||||
this function confirms the process and cancels the pending rollback timer.
|
||||
|
||||
If no apply with rollback session is active, the function has no effect and
|
||||
returns with a "No data" error.
|
||||
|
||||
@class function
|
||||
@name Cursor.confirm
|
||||
@return Boolean whether operation succeeded
|
||||
]]
|
||||
|
||||
---[[
|
||||
Cancels UCI apply process.
|
||||
|
||||
If a previous UCI apply with rollback has been invoked using apply(true),
|
||||
this function cancels the process and rolls back the configuration to the
|
||||
pre-apply state.
|
||||
|
||||
If no apply with rollback session is active, the function has no effect and
|
||||
returns with a "No data" error.
|
||||
|
||||
@class function
|
||||
@name Cursor.rollback
|
||||
@return Boolean whether operation succeeded
|
||||
]]
|
||||
|
||||
---[[
|
||||
Checks whether a pending rollback is scheduled.
|
||||
|
||||
If a previous UCI apply with rollback has been invoked using apply(true),
|
||||
and has not been confirmed or rolled back yet, this function returns true
|
||||
and the remaining time until rollback in seconds. If no rollback is pending,
|
||||
the function returns false. On error, the function returns false and an
|
||||
additional string describing the error.
|
||||
|
||||
@class function
|
||||
@name Cursor.rollback_pending
|
||||
@return Boolean whether rollback is pending
|
||||
@return Remaining time in seconds
|
||||
]]
|
||||
|
||||
---[[
|
||||
Delete all sections of a given type that match certain criteria.
|
||||
|
||||
@class function
|
||||
@name Cursor.delete_all
|
||||
@param config UCI config
|
||||
@param type UCI section type
|
||||
@param comparator Function that will be called for each section and returns
|
||||
a boolean whether to delete the current section (optional)
|
||||
]]
|
||||
|
||||
---[[
|
||||
Create a new section and initialize it with data.
|
||||
|
||||
@class function
|
||||
@name Cursor.section
|
||||
@param config UCI config
|
||||
@param type UCI section type
|
||||
@param name UCI section name (optional)
|
||||
@param values Table of key - value pairs to initialize the section with
|
||||
@return Name of created section
|
||||
]]
|
||||
|
||||
---[[
|
||||
Updated the data of a section using data from a table.
|
||||
|
||||
@class function
|
||||
@name Cursor.tset
|
||||
@param config UCI config
|
||||
@param section UCI section name (optional)
|
||||
@param values Table of key - value pairs to update the section with
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get a boolean option and return it's value as true or false.
|
||||
|
||||
@class function
|
||||
@name Cursor.get_bool
|
||||
@param config UCI config
|
||||
@param section UCI section name
|
||||
@param option UCI option
|
||||
@return Boolean
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get an option or list and return values as table.
|
||||
|
||||
@class function
|
||||
@name Cursor.get_list
|
||||
@param config UCI config
|
||||
@param section UCI section name
|
||||
@param option UCI option
|
||||
@return table. If the option was not found, you will simply get an empty
|
||||
table.
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get the given option from the first section with the given type.
|
||||
|
||||
@class function
|
||||
@name Cursor.get_first
|
||||
@param config UCI config
|
||||
@param type UCI section type
|
||||
@param option UCI option (optional)
|
||||
@param default Default value (optional)
|
||||
@return UCI value
|
||||
]]
|
||||
|
||||
---[[
|
||||
Set given values as list. Setting a list option to an empty list
|
||||
has the same effect as deleting the option.
|
||||
|
||||
@class function
|
||||
@name Cursor.set_list
|
||||
@param config UCI config
|
||||
@param section UCI section name
|
||||
@param option UCI option
|
||||
@param value Value or table. Non-table values will be set as single
|
||||
item UCI list.
|
||||
@return Boolean whether operation succeeded
|
||||
]]
|
||||
|
||||
---[[
|
||||
Create a sub-state of this cursor.
|
||||
|
||||
The sub-state is tied to the parent curser, means it the parent unloads or
|
||||
loads configs, the sub state will do so as well.
|
||||
|
||||
@class function
|
||||
@name Cursor.substate
|
||||
@return UCI state cursor tied to the parent cursor
|
||||
]]
|
||||
|
||||
---[[
|
||||
Add an anonymous section.
|
||||
|
||||
@class function
|
||||
@name Cursor.add
|
||||
@param config UCI config
|
||||
@param type UCI section type
|
||||
@return Name of created section
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get a table of saved but uncommitted changes.
|
||||
|
||||
@class function
|
||||
@name Cursor.changes
|
||||
@param config UCI config
|
||||
@return Table of changes
|
||||
@see Cursor.save
|
||||
]]
|
||||
|
||||
---[[
|
||||
Commit saved changes.
|
||||
|
||||
@class function
|
||||
@name Cursor.commit
|
||||
@param config UCI config
|
||||
@return Boolean whether operation succeeded
|
||||
@see Cursor.revert
|
||||
@see Cursor.save
|
||||
]]
|
||||
|
||||
---[[
|
||||
Deletes a section or an option.
|
||||
|
||||
@class function
|
||||
@name Cursor.delete
|
||||
@param config UCI config
|
||||
@param section UCI section name
|
||||
@param option UCI option (optional)
|
||||
@return Boolean whether operation succeeded
|
||||
]]
|
||||
|
||||
---[[
|
||||
Call a function for every section of a certain type.
|
||||
|
||||
@class function
|
||||
@name Cursor.foreach
|
||||
@param config UCI config
|
||||
@param type UCI section type
|
||||
@param callback Function to be called
|
||||
@return Boolean whether operation succeeded
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get a section type or an option
|
||||
|
||||
@class function
|
||||
@name Cursor.get
|
||||
@param config UCI config
|
||||
@param section UCI section name
|
||||
@param option UCI option (optional)
|
||||
@return UCI value
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get all sections of a config or all values of a section.
|
||||
|
||||
@class function
|
||||
@name Cursor.get_all
|
||||
@param config UCI config
|
||||
@param section UCI section name (optional)
|
||||
@return Table of UCI sections or table of UCI values
|
||||
]]
|
||||
|
||||
---[[
|
||||
Manually load a config.
|
||||
|
||||
@class function
|
||||
@name Cursor.load
|
||||
@param config UCI config
|
||||
@return Boolean whether operation succeeded
|
||||
@see Cursor.save
|
||||
@see Cursor.unload
|
||||
]]
|
||||
|
||||
---[[
|
||||
Revert saved but uncommitted changes.
|
||||
|
||||
@class function
|
||||
@name Cursor.revert
|
||||
@param config UCI config
|
||||
@return Boolean whether operation succeeded
|
||||
@see Cursor.commit
|
||||
@see Cursor.save
|
||||
]]
|
||||
|
||||
---[[
|
||||
Saves changes made to a config to make them committable.
|
||||
|
||||
@class function
|
||||
@name Cursor.save
|
||||
@param config UCI config
|
||||
@return Boolean whether operation succeeded
|
||||
@see Cursor.load
|
||||
@see Cursor.unload
|
||||
]]
|
||||
|
||||
---[[
|
||||
Set a value or create a named section.
|
||||
|
||||
When invoked with three arguments `config`, `sectionname`, `sectiontype`,
|
||||
then a named section of the given type is created.
|
||||
|
||||
When invoked with four arguments `config`, `sectionname`, `optionname` and
|
||||
`optionvalue` then the value of the specified option is set to the given value.
|
||||
|
||||
@class function
|
||||
@name Cursor.set
|
||||
@param config UCI config
|
||||
@param section UCI section name
|
||||
@param option UCI option or UCI section type
|
||||
@param value UCI value or nothing if you want to create a section
|
||||
@return Boolean whether operation succeeded
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get the configuration directory.
|
||||
|
||||
@class function
|
||||
@name Cursor.get_confdir
|
||||
@return Configuration directory
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get the directory for uncomitted changes.
|
||||
|
||||
@class function
|
||||
@name Cursor.get_savedir
|
||||
@return Save directory
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get the effective session ID.
|
||||
|
||||
@class function
|
||||
@name Cursor.get_session_id
|
||||
@return String containing the session ID
|
||||
]]
|
||||
|
||||
---[[
|
||||
Set the configuration directory.
|
||||
|
||||
@class function
|
||||
@name Cursor.set_confdir
|
||||
@param directory UCI configuration directory
|
||||
@return Boolean whether operation succeeded
|
||||
]]
|
||||
|
||||
---[[
|
||||
Set the directory for uncommited changes.
|
||||
|
||||
@class function
|
||||
@name Cursor.set_savedir
|
||||
@param directory UCI changes directory
|
||||
@return Boolean whether operation succeeded
|
||||
]]
|
||||
|
||||
---[[
|
||||
Set the effective session ID.
|
||||
|
||||
@class function
|
||||
@name Cursor.set_session_id
|
||||
@param id String containing the session ID to set
|
||||
@return Boolean whether operation succeeded
|
||||
]]
|
||||
|
||||
---[[
|
||||
Discard changes made to a config.
|
||||
|
||||
@class function
|
||||
@name Cursor.unload
|
||||
@param config UCI config
|
||||
@return Boolean whether operation succeeded
|
||||
@see Cursor.load
|
||||
@see Cursor.save
|
||||
]]
|
||||
|
|
@ -1,73 +0,0 @@
|
|||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
exectime = os.clock()
|
||||
module("luci.sgi.cgi", package.seeall)
|
||||
local ltn12 = require("luci.ltn12")
|
||||
require("nixio.util")
|
||||
require("luci.http")
|
||||
require("luci.sys")
|
||||
require("luci.dispatcher")
|
||||
|
||||
-- Limited source to avoid endless blocking
|
||||
local function limitsource(handle, limit)
|
||||
limit = limit or 0
|
||||
local BLOCKSIZE = ltn12.BLOCKSIZE
|
||||
|
||||
return function()
|
||||
if limit < 1 then
|
||||
handle:close()
|
||||
return nil
|
||||
else
|
||||
local read = (limit > BLOCKSIZE) and BLOCKSIZE or limit
|
||||
limit = limit - read
|
||||
|
||||
local chunk = handle:read(read)
|
||||
if not chunk then handle:close() end
|
||||
return chunk
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function run()
|
||||
local r = luci.http.Request(
|
||||
luci.sys.getenv(),
|
||||
limitsource(io.stdin, tonumber(luci.sys.getenv("CONTENT_LENGTH"))),
|
||||
ltn12.sink.file(io.stderr)
|
||||
)
|
||||
|
||||
local x = coroutine.create(luci.dispatcher.httpdispatch)
|
||||
local hcache = ""
|
||||
local active = true
|
||||
|
||||
while coroutine.status(x) ~= "dead" do
|
||||
local res, id, data1, data2 = coroutine.resume(x, r)
|
||||
|
||||
if not res then
|
||||
print("Status: 500 Internal Server Error")
|
||||
print("Content-Type: text/plain\n")
|
||||
print(id)
|
||||
break;
|
||||
end
|
||||
|
||||
if active then
|
||||
if id == 1 then
|
||||
io.write("Status: " .. tostring(data1) .. " " .. data2 .. "\r\n")
|
||||
elseif id == 2 then
|
||||
hcache = hcache .. data1 .. ": " .. data2 .. "\r\n"
|
||||
elseif id == 3 then
|
||||
io.write(hcache)
|
||||
io.write("\r\n")
|
||||
elseif id == 4 then
|
||||
io.write(tostring(data1 or ""))
|
||||
elseif id == 5 then
|
||||
io.flush()
|
||||
io.close()
|
||||
active = false
|
||||
elseif id == 6 then
|
||||
data1:copyz(nixio.stdout, data2)
|
||||
data1:close()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,89 +0,0 @@
|
|||
-- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
require "nixio.util"
|
||||
require "luci.http"
|
||||
require "luci.sys"
|
||||
require "luci.dispatcher"
|
||||
require "luci.ltn12"
|
||||
|
||||
function handle_request(env)
|
||||
exectime = os.clock()
|
||||
local renv = {
|
||||
CONTENT_LENGTH = env.CONTENT_LENGTH,
|
||||
CONTENT_TYPE = env.CONTENT_TYPE,
|
||||
REQUEST_METHOD = env.REQUEST_METHOD,
|
||||
REQUEST_URI = env.REQUEST_URI,
|
||||
PATH_INFO = env.PATH_INFO,
|
||||
SCRIPT_NAME = env.SCRIPT_NAME:gsub("/+$", ""),
|
||||
SCRIPT_FILENAME = env.SCRIPT_NAME,
|
||||
SERVER_PROTOCOL = env.SERVER_PROTOCOL,
|
||||
QUERY_STRING = env.QUERY_STRING
|
||||
}
|
||||
|
||||
local k, v
|
||||
for k, v in pairs(env.headers) do
|
||||
k = k:upper():gsub("%-", "_")
|
||||
renv["HTTP_" .. k] = v
|
||||
end
|
||||
|
||||
local len = tonumber(env.CONTENT_LENGTH) or 0
|
||||
local function recv()
|
||||
if len > 0 then
|
||||
local rlen, rbuf = uhttpd.recv(4096)
|
||||
if rlen >= 0 then
|
||||
len = len - rlen
|
||||
return rbuf
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local send = uhttpd.send
|
||||
|
||||
local req = luci.http.Request(
|
||||
renv, recv, luci.ltn12.sink.file(io.stderr)
|
||||
)
|
||||
|
||||
|
||||
local x = coroutine.create(luci.dispatcher.httpdispatch)
|
||||
local hcache = { }
|
||||
local active = true
|
||||
|
||||
while coroutine.status(x) ~= "dead" do
|
||||
local res, id, data1, data2 = coroutine.resume(x, req)
|
||||
|
||||
if not res then
|
||||
send("Status: 500 Internal Server Error\r\n")
|
||||
send("Content-Type: text/plain\r\n\r\n")
|
||||
send(tostring(id))
|
||||
break
|
||||
end
|
||||
|
||||
if active then
|
||||
if id == 1 then
|
||||
send("Status: ")
|
||||
send(tostring(data1))
|
||||
send(" ")
|
||||
send(tostring(data2))
|
||||
send("\r\n")
|
||||
elseif id == 2 then
|
||||
hcache[data1] = data2
|
||||
elseif id == 3 then
|
||||
for k, v in pairs(hcache) do
|
||||
send(tostring(k))
|
||||
send(": ")
|
||||
send(tostring(v))
|
||||
send("\r\n")
|
||||
end
|
||||
send("\r\n")
|
||||
elseif id == 4 then
|
||||
send(tostring(data1 or ""))
|
||||
elseif id == 5 then
|
||||
active = false
|
||||
elseif id == 6 then
|
||||
data1:copyz(nixio.stdout, data2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,6 +0,0 @@
|
|||
-- Copyright 2009 Steven Barth <steven@midlink.org>
|
||||
-- Copyright 2009 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local util = require "luci.util"
|
||||
module("luci.store", util.threadlocal)
|
|
@ -1,515 +0,0 @@
|
|||
-- Copyright 2008 Steven Barth <steven@midlink.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local io = require "io"
|
||||
local os = require "os"
|
||||
local table = require "table"
|
||||
local nixio = require "nixio"
|
||||
local fs = require "nixio.fs"
|
||||
local uci = require "luci.model.uci"
|
||||
local ntm = require "luci.model.network"
|
||||
|
||||
local luci = {}
|
||||
luci.util = require "luci.util"
|
||||
luci.ip = require "luci.ip"
|
||||
|
||||
local tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select =
|
||||
tonumber, ipairs, pairs, pcall, type, next, setmetatable, require, select
|
||||
|
||||
|
||||
module "luci.sys"
|
||||
|
||||
function call(...)
|
||||
return os.execute(...) / 256
|
||||
end
|
||||
|
||||
exec = luci.util.exec
|
||||
|
||||
function mounts()
|
||||
local data = {}
|
||||
local k = {"fs", "blocks", "used", "available", "percent", "mountpoint"}
|
||||
local ps = luci.util.execi("df")
|
||||
|
||||
if not ps then
|
||||
return
|
||||
else
|
||||
ps()
|
||||
end
|
||||
|
||||
for line in ps do
|
||||
local row = {}
|
||||
|
||||
local j = 1
|
||||
for value in line:gmatch("[^%s]+") do
|
||||
row[k[j]] = value
|
||||
j = j + 1
|
||||
end
|
||||
|
||||
if row[k[1]] then
|
||||
|
||||
-- this is a rather ugly workaround to cope with wrapped lines in
|
||||
-- the df output:
|
||||
--
|
||||
-- /dev/scsi/host0/bus0/target0/lun0/part3
|
||||
-- 114382024 93566472 15005244 86% /mnt/usb
|
||||
--
|
||||
|
||||
if not row[k[2]] then
|
||||
j = 2
|
||||
line = ps()
|
||||
for value in line:gmatch("[^%s]+") do
|
||||
row[k[j]] = value
|
||||
j = j + 1
|
||||
end
|
||||
end
|
||||
|
||||
table.insert(data, row)
|
||||
end
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
-- containing the whole environment is returned otherwise this function returns
|
||||
-- the corresponding string value for the given name or nil if no such variable
|
||||
-- exists.
|
||||
getenv = nixio.getenv
|
||||
|
||||
function hostname(newname)
|
||||
if type(newname) == "string" and #newname > 0 then
|
||||
fs.writefile( "/proc/sys/kernel/hostname", newname )
|
||||
return newname
|
||||
else
|
||||
return nixio.uname().nodename
|
||||
end
|
||||
end
|
||||
|
||||
function httpget(url, stream, target)
|
||||
if not target then
|
||||
local source = stream and io.popen or luci.util.exec
|
||||
return source("wget -qO- %s" % luci.util.shellquote(url))
|
||||
else
|
||||
return os.execute("wget -qO %s %s" %
|
||||
{luci.util.shellquote(target), luci.util.shellquote(url)})
|
||||
end
|
||||
end
|
||||
|
||||
function reboot()
|
||||
return os.execute("reboot >/dev/null 2>&1")
|
||||
end
|
||||
|
||||
function syslog()
|
||||
return luci.util.exec("logread")
|
||||
end
|
||||
|
||||
function dmesg()
|
||||
return luci.util.exec("dmesg")
|
||||
end
|
||||
|
||||
function uniqueid(bytes)
|
||||
local rand = fs.readfile("/dev/urandom", bytes)
|
||||
return rand and nixio.bin.hexlify(rand)
|
||||
end
|
||||
|
||||
function uptime()
|
||||
return nixio.sysinfo().uptime
|
||||
end
|
||||
|
||||
|
||||
net = {}
|
||||
|
||||
local function _nethints(what, callback)
|
||||
local _, k, e, mac, ip, name
|
||||
local cur = uci.cursor()
|
||||
local ifn = { }
|
||||
local hosts = { }
|
||||
local lookup = { }
|
||||
|
||||
local function _add(i, ...)
|
||||
local k = select(i, ...)
|
||||
if k then
|
||||
if not hosts[k] then hosts[k] = { } end
|
||||
hosts[k][1] = select(1, ...) or hosts[k][1]
|
||||
hosts[k][2] = select(2, ...) or hosts[k][2]
|
||||
hosts[k][3] = select(3, ...) or hosts[k][3]
|
||||
hosts[k][4] = select(4, ...) or hosts[k][4]
|
||||
end
|
||||
end
|
||||
|
||||
luci.ip.neighbors(nil, function(neigh)
|
||||
if neigh.mac and neigh.family == 4 then
|
||||
_add(what, neigh.mac:string(), neigh.dest:string(), nil, nil)
|
||||
elseif neigh.mac and neigh.family == 6 then
|
||||
_add(what, neigh.mac:string(), nil, neigh.dest:string(), nil)
|
||||
end
|
||||
end)
|
||||
|
||||
if fs.access("/etc/ethers") then
|
||||
for e in io.lines("/etc/ethers") do
|
||||
mac, name = e:match("^([a-fA-F0-9:-]+)%s+(%S+)")
|
||||
mac = luci.ip.checkmac(mac)
|
||||
if mac and name then
|
||||
if luci.ip.checkip4(name) then
|
||||
_add(what, mac, name, nil, nil)
|
||||
else
|
||||
_add(what, mac, nil, nil, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cur:foreach("dhcp", "dnsmasq",
|
||||
function(s)
|
||||
if s.leasefile and fs.access(s.leasefile) then
|
||||
for e in io.lines(s.leasefile) do
|
||||
mac, ip, name = e:match("^%d+ (%S+) (%S+) (%S+)")
|
||||
mac = luci.ip.checkmac(mac)
|
||||
if mac and ip then
|
||||
_add(what, mac, ip, nil, name ~= "*" and name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
cur:foreach("dhcp", "host",
|
||||
function(s)
|
||||
for mac in luci.util.imatch(s.mac) do
|
||||
mac = luci.ip.checkmac(mac)
|
||||
if mac then
|
||||
_add(what, mac, s.ip, nil, s.name)
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
for _, e in ipairs(nixio.getifaddrs()) do
|
||||
if e.name ~= "lo" then
|
||||
ifn[e.name] = ifn[e.name] or { }
|
||||
if e.family == "packet" and e.addr and #e.addr == 17 then
|
||||
ifn[e.name][1] = e.addr:upper()
|
||||
elseif e.family == "inet" then
|
||||
ifn[e.name][2] = e.addr
|
||||
elseif e.family == "inet6" then
|
||||
ifn[e.name][3] = e.addr
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for _, e in pairs(ifn) do
|
||||
if e[what] and (e[2] or e[3]) then
|
||||
_add(what, e[1], e[2], e[3], e[4])
|
||||
end
|
||||
end
|
||||
|
||||
for _, e in pairs(hosts) do
|
||||
lookup[#lookup+1] = (what > 1) and e[what] or (e[2] or e[3])
|
||||
end
|
||||
|
||||
if #lookup > 0 then
|
||||
lookup = luci.util.ubus("network.rrdns", "lookup", {
|
||||
addrs = lookup,
|
||||
timeout = 250,
|
||||
limit = 1000
|
||||
}) or { }
|
||||
end
|
||||
|
||||
for _, e in luci.util.kspairs(hosts) do
|
||||
callback(e[1], e[2], e[3], lookup[e[2]] or lookup[e[3]] or e[4])
|
||||
end
|
||||
end
|
||||
|
||||
-- Each entry contains the values in the following order:
|
||||
-- [ "mac", "name" ]
|
||||
function net.mac_hints(callback)
|
||||
if callback then
|
||||
_nethints(1, function(mac, v4, v6, name)
|
||||
name = name or v4
|
||||
if name and name ~= mac then
|
||||
callback(mac, name or v4)
|
||||
end
|
||||
end)
|
||||
else
|
||||
local rv = { }
|
||||
_nethints(1, function(mac, v4, v6, name)
|
||||
name = name or v4
|
||||
if name and name ~= mac then
|
||||
rv[#rv+1] = { mac, name or v4 }
|
||||
end
|
||||
end)
|
||||
return rv
|
||||
end
|
||||
end
|
||||
|
||||
-- Each entry contains the values in the following order:
|
||||
-- [ "ip", "name" ]
|
||||
function net.ipv4_hints(callback)
|
||||
if callback then
|
||||
_nethints(2, function(mac, v4, v6, name)
|
||||
name = name or mac
|
||||
if name and name ~= v4 then
|
||||
callback(v4, name)
|
||||
end
|
||||
end)
|
||||
else
|
||||
local rv = { }
|
||||
_nethints(2, function(mac, v4, v6, name)
|
||||
name = name or mac
|
||||
if name and name ~= v4 then
|
||||
rv[#rv+1] = { v4, name }
|
||||
end
|
||||
end)
|
||||
return rv
|
||||
end
|
||||
end
|
||||
|
||||
-- Each entry contains the values in the following order:
|
||||
-- [ "ip", "name" ]
|
||||
function net.ipv6_hints(callback)
|
||||
if callback then
|
||||
_nethints(3, function(mac, v4, v6, name)
|
||||
name = name or mac
|
||||
if name and name ~= v6 then
|
||||
callback(v6, name)
|
||||
end
|
||||
end)
|
||||
else
|
||||
local rv = { }
|
||||
_nethints(3, function(mac, v4, v6, name)
|
||||
name = name or mac
|
||||
if name and name ~= v6 then
|
||||
rv[#rv+1] = { v6, name }
|
||||
end
|
||||
end)
|
||||
return rv
|
||||
end
|
||||
end
|
||||
|
||||
function net.host_hints(callback)
|
||||
if callback then
|
||||
_nethints(1, function(mac, v4, v6, name)
|
||||
if mac and mac ~= "00:00:00:00:00:00" and (v4 or v6 or name) then
|
||||
callback(mac, v4, v6, name)
|
||||
end
|
||||
end)
|
||||
else
|
||||
local rv = { }
|
||||
_nethints(1, function(mac, v4, v6, name)
|
||||
if mac and mac ~= "00:00:00:00:00:00" and (v4 or v6 or name) then
|
||||
local e = { }
|
||||
if v4 then e.ipv4 = v4 end
|
||||
if v6 then e.ipv6 = v6 end
|
||||
if name then e.name = name end
|
||||
rv[mac] = e
|
||||
end
|
||||
end)
|
||||
return rv
|
||||
end
|
||||
end
|
||||
|
||||
function net.conntrack(callback)
|
||||
local ok, nfct = pcall(io.lines, "/proc/net/nf_conntrack")
|
||||
if not ok or not nfct then
|
||||
return nil
|
||||
end
|
||||
|
||||
local line, connt = nil, (not callback) and { }
|
||||
for line in nfct do
|
||||
local fam, l3, l4, timeout, tuples =
|
||||
line:match("^(ipv[46]) +(%d+) +%S+ +(%d+) +(%d+) +(.+)$")
|
||||
|
||||
if fam and l3 and l4 and timeout and not tuples:match("^TIME_WAIT ") then
|
||||
l4 = nixio.getprotobynumber(l4)
|
||||
|
||||
local entry = {
|
||||
bytes = 0,
|
||||
packets = 0,
|
||||
layer3 = fam,
|
||||
layer4 = l4 and l4.name or "unknown",
|
||||
timeout = tonumber(timeout, 10)
|
||||
}
|
||||
|
||||
local key, val
|
||||
for key, val in tuples:gmatch("(%w+)=(%S+)") do
|
||||
if key == "bytes" or key == "packets" then
|
||||
entry[key] = entry[key] + tonumber(val, 10)
|
||||
elseif key == "src" or key == "dst" then
|
||||
if entry[key] == nil then
|
||||
entry[key] = luci.ip.new(val):string()
|
||||
end
|
||||
elseif key == "sport" or key == "dport" then
|
||||
if entry[key] == nil then
|
||||
entry[key] = val
|
||||
end
|
||||
elseif val then
|
||||
entry[key] = val
|
||||
end
|
||||
end
|
||||
|
||||
if callback then
|
||||
callback(entry)
|
||||
else
|
||||
connt[#connt+1] = entry
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return callback and true or connt
|
||||
end
|
||||
|
||||
function net.devices()
|
||||
local devs = {}
|
||||
local seen = {}
|
||||
for k, v in ipairs(nixio.getifaddrs()) do
|
||||
if v.name and not seen[v.name] then
|
||||
seen[v.name] = true
|
||||
devs[#devs+1] = v.name
|
||||
end
|
||||
end
|
||||
return devs
|
||||
end
|
||||
|
||||
|
||||
process = {}
|
||||
|
||||
function process.info(key)
|
||||
local s = {uid = nixio.getuid(), gid = nixio.getgid()}
|
||||
return not key and s or s[key]
|
||||
end
|
||||
|
||||
function process.list()
|
||||
local data = {}
|
||||
local k
|
||||
local ps = luci.util.execi("/bin/busybox top -bn1")
|
||||
|
||||
if not ps then
|
||||
return
|
||||
end
|
||||
|
||||
for line in ps do
|
||||
local pid, ppid, user, stat, vsz, mem, cpu, cmd = line:match(
|
||||
"^ *(%d+) +(%d+) +(%S.-%S) +([RSDZTW][W ][<N ]) +(%d+) +(%d+%%) +(%d+%%) +(.+)"
|
||||
)
|
||||
|
||||
local idx = tonumber(pid)
|
||||
if idx then
|
||||
data[idx] = {
|
||||
['PID'] = pid,
|
||||
['PPID'] = ppid,
|
||||
['USER'] = user,
|
||||
['STAT'] = stat,
|
||||
['VSZ'] = vsz,
|
||||
['%MEM'] = mem,
|
||||
['%CPU'] = cpu,
|
||||
['COMMAND'] = cmd
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
function process.setgroup(gid)
|
||||
return nixio.setgid(gid)
|
||||
end
|
||||
|
||||
function process.setuser(uid)
|
||||
return nixio.setuid(uid)
|
||||
end
|
||||
|
||||
process.signal = nixio.kill
|
||||
|
||||
|
||||
user = {}
|
||||
|
||||
-- { "uid", "gid", "name", "passwd", "dir", "shell", "gecos" }
|
||||
user.getuser = nixio.getpw
|
||||
|
||||
function user.getpasswd(username)
|
||||
local pwe = nixio.getsp and nixio.getsp(username) or nixio.getpw(username)
|
||||
local pwh = pwe and (pwe.pwdp or pwe.passwd)
|
||||
if not pwh or #pwh < 1 or pwh == "!" or pwh == "x" then
|
||||
return nil, pwe
|
||||
else
|
||||
return pwh, pwe
|
||||
end
|
||||
end
|
||||
|
||||
function user.checkpasswd(username, pass)
|
||||
local pwh, pwe = user.getpasswd(username)
|
||||
if pwe then
|
||||
return (pwh == nil or nixio.crypt(pass, pwh) == pwh)
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function user.setpasswd(username, password)
|
||||
return os.execute("(echo %s; sleep 1; echo %s) | passwd %s >/dev/null 2>&1" %{
|
||||
luci.util.shellquote(password),
|
||||
luci.util.shellquote(password),
|
||||
luci.util.shellquote(username)
|
||||
})
|
||||
end
|
||||
|
||||
|
||||
wifi = {}
|
||||
|
||||
function wifi.getiwinfo(ifname)
|
||||
ntm.init()
|
||||
|
||||
local wnet = ntm:get_wifinet(ifname)
|
||||
if wnet and wnet.iwinfo then
|
||||
return wnet.iwinfo
|
||||
end
|
||||
|
||||
local wdev = ntm:get_wifidev(ifname)
|
||||
if wdev and wdev.iwinfo then
|
||||
return wdev.iwinfo
|
||||
end
|
||||
|
||||
return { ifname = ifname }
|
||||
end
|
||||
|
||||
|
||||
init = {}
|
||||
init.dir = "/etc/init.d/"
|
||||
|
||||
function init.names()
|
||||
local names = { }
|
||||
for name in fs.glob(init.dir.."*") do
|
||||
names[#names+1] = fs.basename(name)
|
||||
end
|
||||
return names
|
||||
end
|
||||
|
||||
function init.index(name)
|
||||
if fs.access(init.dir..name) then
|
||||
return call("env -i sh -c 'source %s%s enabled; exit ${START:-255}' >/dev/null"
|
||||
%{ init.dir, name })
|
||||
end
|
||||
end
|
||||
|
||||
local function init_action(action, name)
|
||||
if fs.access(init.dir..name) then
|
||||
return call("env -i %s%s %s >/dev/null" %{ init.dir, name, action })
|
||||
end
|
||||
end
|
||||
|
||||
function init.enabled(name)
|
||||
return (init_action("enabled", name) == 0)
|
||||
end
|
||||
|
||||
function init.enable(name)
|
||||
return (init_action("enable", name) == 1)
|
||||
end
|
||||
|
||||
function init.disable(name)
|
||||
return (init_action("disable", name) == 0)
|
||||
end
|
||||
|
||||
function init.start(name)
|
||||
return (init_action("start", name) == 0)
|
||||
end
|
||||
|
||||
function init.stop(name)
|
||||
return (init_action("stop", name) == 0)
|
||||
end
|
|
@ -1,405 +0,0 @@
|
|||
---[[
|
||||
LuCI Linux and POSIX system utilities.
|
||||
]]
|
||||
module "luci.sys"
|
||||
|
||||
---[[
|
||||
Execute a given shell command and return the error code
|
||||
|
||||
@class function
|
||||
@name call
|
||||
@param ... Command to call
|
||||
@return Error code of the command
|
||||
]]
|
||||
|
||||
---[[
|
||||
Execute a given shell command and capture its standard output
|
||||
|
||||
@class function
|
||||
@name exec
|
||||
@param command Command to call
|
||||
@return String containg the return the output of the command
|
||||
]]
|
||||
|
||||
---[[
|
||||
Retrieve information about currently mounted file systems.
|
||||
|
||||
@class function
|
||||
@name mounts
|
||||
@return Table containing mount information
|
||||
]]
|
||||
|
||||
---[[
|
||||
Retrieve environment variables. If no variable is given then a table
|
||||
|
||||
containing the whole environment is returned otherwise this function returns
|
||||
the corresponding string value for the given name or nil if no such variable
|
||||
exists.
|
||||
@class function
|
||||
@name getenv
|
||||
@param var Name of the environment variable to retrieve (optional)
|
||||
@return String containg the value of the specified variable
|
||||
@return Table containing all variables if no variable name is given
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get or set the current hostname.
|
||||
|
||||
@class function
|
||||
@name hostname
|
||||
@param String containing a new hostname to set (optional)
|
||||
@return String containing the system hostname
|
||||
]]
|
||||
|
||||
---[[
|
||||
Returns the contents of a documented referred by an URL.
|
||||
|
||||
@class function
|
||||
@name httpget
|
||||
@param url The URL to retrieve
|
||||
@param stream Return a stream instead of a buffer
|
||||
@param target Directly write to target file name
|
||||
@return String containing the contents of given the URL
|
||||
]]
|
||||
|
||||
---[[
|
||||
Initiate a system reboot.
|
||||
|
||||
@class function
|
||||
@name reboot
|
||||
@return Return value of os.execute()
|
||||
]]
|
||||
|
||||
---[[
|
||||
Retrieves the output of the "logread" command.
|
||||
|
||||
@class function
|
||||
@name syslog
|
||||
@return String containing the current log buffer
|
||||
]]
|
||||
|
||||
---[[
|
||||
Retrieves the output of the "dmesg" command.
|
||||
|
||||
@class function
|
||||
@name dmesg
|
||||
@return String containing the current log buffer
|
||||
]]
|
||||
|
||||
---[[
|
||||
Generates a random id with specified length.
|
||||
|
||||
@class function
|
||||
@name uniqueid
|
||||
@param bytes Number of bytes for the unique id
|
||||
@return String containing hex encoded id
|
||||
]]
|
||||
|
||||
---[[
|
||||
Returns the current system uptime stats.
|
||||
|
||||
@class function
|
||||
@name uptime
|
||||
@return String containing total uptime in seconds
|
||||
]]
|
||||
|
||||
---[[
|
||||
LuCI system utilities / network related functions.
|
||||
|
||||
@class module
|
||||
@name luci.sys.net
|
||||
]]
|
||||
|
||||
---[[
|
||||
Returns the current arp-table entries as two-dimensional table.
|
||||
|
||||
@class function
|
||||
@name net.arptable
|
||||
@return Table of table containing the current arp entries.
|
||||
-- The following fields are defined for arp entry objects:
|
||||
-- { "IP address", "HW address", "HW type", "Flags", "Mask", "Device" }
|
||||
]]
|
||||
|
||||
---[[
|
||||
Returns a two-dimensional table of mac address hints.
|
||||
|
||||
@class function
|
||||
@name net.mac_hints
|
||||
@return Table of table containing known hosts from various sources.
|
||||
Each entry contains the values in the following order:
|
||||
[ "mac", "name" ]
|
||||
]]
|
||||
|
||||
---[[
|
||||
Returns a two-dimensional table of IPv4 address hints.
|
||||
|
||||
@class function
|
||||
@name net.ipv4_hints
|
||||
@return Table of table containing known hosts from various sources.
|
||||
Each entry contains the values in the following order:
|
||||
[ "ip", "name" ]
|
||||
]]
|
||||
|
||||
---[[
|
||||
Returns a two-dimensional table of IPv6 address hints.
|
||||
|
||||
@class function
|
||||
@name net.ipv6_hints
|
||||
@return Table of table containing known hosts from various sources.
|
||||
Each entry contains the values in the following order:
|
||||
[ "ip", "name" ]
|
||||
]]
|
||||
|
||||
---[[
|
||||
Returns a two-dimensional table of host hints.
|
||||
|
||||
@class function
|
||||
@name net.host_hints
|
||||
@return Table of table containing known hosts from various sources,
|
||||
indexed by mac address. Each subtable contains at least one
|
||||
of the fields "name", "ipv4" or "ipv6".
|
||||
]]
|
||||
|
||||
---[[
|
||||
Returns conntrack information
|
||||
|
||||
@class function
|
||||
@name net.conntrack
|
||||
@return Table with the currently tracked IP connections
|
||||
]]
|
||||
|
||||
---[[
|
||||
Determine the names of available network interfaces.
|
||||
|
||||
@class function
|
||||
@name net.devices
|
||||
@return Table containing all current interface names
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return information about available network interfaces.
|
||||
|
||||
@class function
|
||||
@name net.deviceinfo
|
||||
@return Table containing all current interface names and their information
|
||||
]]
|
||||
|
||||
---[[
|
||||
Returns the current kernel routing table entries.
|
||||
|
||||
@class function
|
||||
@name net.routes
|
||||
@return Table of tables with properties of the corresponding routes.
|
||||
-- The following fields are defined for route entry tables:
|
||||
-- { "dest", "gateway", "metric", "refcount", "usecount", "irtt",
|
||||
-- "flags", "device" }
|
||||
]]
|
||||
|
||||
---[[
|
||||
Returns the current ipv6 kernel routing table entries.
|
||||
|
||||
@class function
|
||||
@name net.routes6
|
||||
@return Table of tables with properties of the corresponding routes.
|
||||
-- The following fields are defined for route entry tables:
|
||||
-- { "source", "dest", "nexthop", "metric", "refcount", "usecount",
|
||||
-- "flags", "device" }
|
||||
]]
|
||||
|
||||
---[[
|
||||
Tests whether the given host responds to ping probes.
|
||||
|
||||
@class function
|
||||
@name net.pingtest
|
||||
@param host String containing a hostname or IPv4 address
|
||||
@return Number containing 0 on success and >= 1 on error
|
||||
]]
|
||||
|
||||
---[[
|
||||
LuCI system utilities / process related functions.
|
||||
|
||||
@class module
|
||||
@name luci.sys.process
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get the current process id.
|
||||
|
||||
@class function
|
||||
@name process.info
|
||||
@return Number containing the current pid
|
||||
]]
|
||||
|
||||
---[[
|
||||
Retrieve information about currently running processes.
|
||||
|
||||
@class function
|
||||
@name process.list
|
||||
@return Table containing process information
|
||||
]]
|
||||
|
||||
---[[
|
||||
Set the gid of a process identified by given pid.
|
||||
|
||||
@class function
|
||||
@name process.setgroup
|
||||
@param gid Number containing the Unix group id
|
||||
@return Boolean indicating successful operation
|
||||
@return String containing the error message if failed
|
||||
@return Number containing the error code if failed
|
||||
]]
|
||||
|
||||
---[[
|
||||
Set the uid of a process identified by given pid.
|
||||
|
||||
@class function
|
||||
@name process.setuser
|
||||
@param uid Number containing the Unix user id
|
||||
@return Boolean indicating successful operation
|
||||
@return String containing the error message if failed
|
||||
@return Number containing the error code if failed
|
||||
]]
|
||||
|
||||
---[[
|
||||
Send a signal to a process identified by given pid.
|
||||
|
||||
@class function
|
||||
@name process.signal
|
||||
@param pid Number containing the process id
|
||||
@param sig Signal to send (default: 15 [SIGTERM])
|
||||
@return Boolean indicating successful operation
|
||||
@return Number containing the error code if failed
|
||||
]]
|
||||
|
||||
---[[
|
||||
LuCI system utilities / user related functions.
|
||||
|
||||
@class module
|
||||
@name luci.sys.user
|
||||
]]
|
||||
|
||||
---[[
|
||||
Retrieve user informations for given uid.
|
||||
|
||||
@class function
|
||||
@name getuser
|
||||
@param uid Number containing the Unix user id
|
||||
@return Table containing the following fields:
|
||||
-- { "uid", "gid", "name", "passwd", "dir", "shell", "gecos" }
|
||||
]]
|
||||
|
||||
---[[
|
||||
Retrieve the current user password hash.
|
||||
|
||||
@class function
|
||||
@name user.getpasswd
|
||||
@param username String containing the username to retrieve the password for
|
||||
@return String containing the hash or nil if no password is set.
|
||||
@return Password database entry
|
||||
]]
|
||||
|
||||
---[[
|
||||
Test whether given string matches the password of a given system user.
|
||||
|
||||
@class function
|
||||
@name user.checkpasswd
|
||||
@param username String containing the Unix user name
|
||||
@param pass String containing the password to compare
|
||||
@return Boolean indicating wheather the passwords are equal
|
||||
]]
|
||||
|
||||
---[[
|
||||
Change the password of given user.
|
||||
|
||||
@class function
|
||||
@name user.setpasswd
|
||||
@param username String containing the Unix user name
|
||||
@param password String containing the password to compare
|
||||
@return Number containing 0 on success and >= 1 on error
|
||||
]]
|
||||
|
||||
---[[
|
||||
LuCI system utilities / wifi related functions.
|
||||
|
||||
@class module
|
||||
@name luci.sys.wifi
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get wireless information for given interface.
|
||||
|
||||
@class function
|
||||
@name wifi.getiwinfo
|
||||
@param ifname String containing the interface name
|
||||
@return A wrapped iwinfo object instance
|
||||
]]
|
||||
|
||||
---[[
|
||||
LuCI system utilities / init related functions.
|
||||
|
||||
@class module
|
||||
@name luci.sys.init
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get the names of all installed init scripts
|
||||
|
||||
@class function
|
||||
@name init.names
|
||||
@return Table containing the names of all inistalled init scripts
|
||||
]]
|
||||
|
||||
---[[
|
||||
Get the index of he given init script
|
||||
|
||||
@class function
|
||||
@name init.index
|
||||
@param name Name of the init script
|
||||
@return Numeric index value
|
||||
]]
|
||||
|
||||
---[[
|
||||
Test whether the given init script is enabled
|
||||
|
||||
@class function
|
||||
@name init.enabled
|
||||
@param name Name of the init script
|
||||
@return Boolean indicating whether init is enabled
|
||||
]]
|
||||
|
||||
---[[
|
||||
Enable the given init script
|
||||
|
||||
@class function
|
||||
@name init.enable
|
||||
@param name Name of the init script
|
||||
@return Boolean indicating success
|
||||
]]
|
||||
|
||||
---[[
|
||||
Disable the given init script
|
||||
|
||||
@class function
|
||||
@name init.disable
|
||||
@param name Name of the init script
|
||||
@return Boolean indicating success
|
||||
]]
|
||||
|
||||
---[[
|
||||
Start the given init script
|
||||
|
||||
@class function
|
||||
@name init.start
|
||||
@param name Name of the init script
|
||||
@return Boolean indicating success
|
||||
]]
|
||||
|
||||
---[[
|
||||
Stop the given init script
|
||||
|
||||
@class function
|
||||
@name init.stop
|
||||
@param name Name of the init script
|
||||
@return Boolean indicating success
|
||||
]]
|
||||
|
|
@ -1,374 +0,0 @@
|
|||
--[[
|
||||
|
||||
Iptables parser and query library
|
||||
(c) 2008-2009 Jo-Philipp Wich <jow@openwrt.org>
|
||||
(c) 2008-2009 Steven Barth <steven@midlink.org>
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
$Id$
|
||||
|
||||
]]--
|
||||
|
||||
local luci = {}
|
||||
luci.util = require "luci.util"
|
||||
luci.sys = require "luci.sys"
|
||||
luci.ip = require "luci.ip"
|
||||
|
||||
local pcall = pcall
|
||||
local io = require "io"
|
||||
local tonumber, ipairs, table = tonumber, ipairs, table
|
||||
|
||||
module("luci.sys.iptparser")
|
||||
|
||||
IptParser = luci.util.class()
|
||||
|
||||
function IptParser.__init__( self, family )
|
||||
self._family = (tonumber(family) == 6) and 6 or 4
|
||||
self._rules = { }
|
||||
self._chains = { }
|
||||
self._tables = { }
|
||||
|
||||
local t = self._tables
|
||||
local s = self:_supported_tables(self._family)
|
||||
|
||||
if s.filter then t[#t+1] = "filter" end
|
||||
if s.nat then t[#t+1] = "nat" end
|
||||
if s.mangle then t[#t+1] = "mangle" end
|
||||
if s.raw then t[#t+1] = "raw" end
|
||||
|
||||
if self._family == 4 then
|
||||
self._nulladdr = "0.0.0.0/0"
|
||||
self._command = "iptables -t %s --line-numbers -nxvL"
|
||||
else
|
||||
self._nulladdr = "::/0"
|
||||
self._command = "ip6tables -t %s --line-numbers -nxvL"
|
||||
end
|
||||
|
||||
self:_parse_rules()
|
||||
end
|
||||
|
||||
function IptParser._supported_tables( self, family )
|
||||
local tables = { }
|
||||
local ok, lines = pcall(io.lines,
|
||||
(family == 6) and "/proc/net/ip6_tables_names"
|
||||
or "/proc/net/ip_tables_names")
|
||||
|
||||
if ok and lines then
|
||||
local line
|
||||
for line in lines do
|
||||
tables[line] = true
|
||||
end
|
||||
end
|
||||
|
||||
return tables
|
||||
end
|
||||
|
||||
-- search criteria as only argument. If args is nil or an empty table then all
|
||||
-- rules will be returned.
|
||||
--
|
||||
-- The following keys in the args table are recognized:
|
||||
-- <ul>
|
||||
-- <li> table - Match rules that are located within the given table
|
||||
-- <li> chain - Match rules that are located within the given chain
|
||||
-- <li> target - Match rules with the given target
|
||||
-- <li> protocol - Match rules that match the given protocol, rules with
|
||||
-- protocol "all" are always matched
|
||||
-- <li> source - Match rules with the given source, rules with source
|
||||
-- "0.0.0.0/0" (::/0) are always matched
|
||||
-- <li> destination - Match rules with the given destination, rules with
|
||||
-- destination "0.0.0.0/0" (::/0) are always matched
|
||||
-- <li> inputif - Match rules with the given input interface, rules
|
||||
-- with input interface "*" (=all) are always matched
|
||||
-- <li> outputif - Match rules with the given output interface, rules
|
||||
-- with output interface "*" (=all) are always matched
|
||||
-- <li> flags - Match rules that match the given flags, current
|
||||
-- supported values are "-f" (--fragment)
|
||||
-- and "!f" (! --fragment)
|
||||
-- <li> options - Match rules containing all given options
|
||||
-- </ul>
|
||||
-- The return value is a list of tables representing the matched rules.
|
||||
-- Each rule table contains the following fields:
|
||||
-- <ul>
|
||||
-- <li> index - The index number of the rule
|
||||
-- <li> table - The table where the rule is located, can be one
|
||||
-- of "filter", "nat" or "mangle"
|
||||
-- <li> chain - The chain where the rule is located, e.g. "INPUT"
|
||||
-- or "postrouting_wan"
|
||||
-- <li> target - The rule target, e.g. "REJECT" or "DROP"
|
||||
-- <li> protocol The matching protocols, e.g. "all" or "tcp"
|
||||
-- <li> flags - Special rule options ("--", "-f" or "!f")
|
||||
-- <li> inputif - Input interface of the rule, e.g. "eth0.0"
|
||||
-- or "*" for all interfaces
|
||||
-- <li> outputif - Output interface of the rule,e.g. "eth0.0"
|
||||
-- or "*" for all interfaces
|
||||
-- <li> source - The source ip range, e.g. "0.0.0.0/0" (::/0)
|
||||
-- <li> destination - The destination ip range, e.g. "0.0.0.0/0" (::/0)
|
||||
-- <li> options - A list of specific options of the rule,
|
||||
-- e.g. { "reject-with", "tcp-reset" }
|
||||
-- <li> packets - The number of packets matched by the rule
|
||||
-- <li> bytes - The number of total bytes matched by the rule
|
||||
-- </ul>
|
||||
-- Example:
|
||||
-- <pre>
|
||||
-- ip = luci.sys.iptparser.IptParser()
|
||||
-- result = ip.find( {
|
||||
-- target="REJECT",
|
||||
-- protocol="tcp",
|
||||
-- options={ "reject-with", "tcp-reset" }
|
||||
-- } )
|
||||
-- </pre>
|
||||
-- This will match all rules with target "-j REJECT",
|
||||
-- protocol "-p tcp" (or "-p all")
|
||||
-- and the option "--reject-with tcp-reset".
|
||||
function IptParser.find( self, args )
|
||||
|
||||
local args = args or { }
|
||||
local rv = { }
|
||||
|
||||
args.source = args.source and self:_parse_addr(args.source)
|
||||
args.destination = args.destination and self:_parse_addr(args.destination)
|
||||
|
||||
for i, rule in ipairs(self._rules) do
|
||||
local match = true
|
||||
|
||||
-- match table
|
||||
if not ( not args.table or args.table:lower() == rule.table ) then
|
||||
match = false
|
||||
end
|
||||
|
||||
-- match chain
|
||||
if not ( match == true and (
|
||||
not args.chain or args.chain == rule.chain
|
||||
) ) then
|
||||
match = false
|
||||
end
|
||||
|
||||
-- match target
|
||||
if not ( match == true and (
|
||||
not args.target or args.target == rule.target
|
||||
) ) then
|
||||
match = false
|
||||
end
|
||||
|
||||
-- match protocol
|
||||
if not ( match == true and (
|
||||
not args.protocol or rule.protocol == "all" or
|
||||
args.protocol:lower() == rule.protocol
|
||||
) ) then
|
||||
match = false
|
||||
end
|
||||
|
||||
-- match source
|
||||
if not ( match == true and (
|
||||
not args.source or rule.source == self._nulladdr or
|
||||
self:_parse_addr(rule.source):contains(args.source)
|
||||
) ) then
|
||||
match = false
|
||||
end
|
||||
|
||||
-- match destination
|
||||
if not ( match == true and (
|
||||
not args.destination or rule.destination == self._nulladdr or
|
||||
self:_parse_addr(rule.destination):contains(args.destination)
|
||||
) ) then
|
||||
match = false
|
||||
end
|
||||
|
||||
-- match input interface
|
||||
if not ( match == true and (
|
||||
not args.inputif or rule.inputif == "*" or
|
||||
args.inputif == rule.inputif
|
||||
) ) then
|
||||
match = false
|
||||
end
|
||||
|
||||
-- match output interface
|
||||
if not ( match == true and (
|
||||
not args.outputif or rule.outputif == "*" or
|
||||
args.outputif == rule.outputif
|
||||
) ) then
|
||||
match = false
|
||||
end
|
||||
|
||||
-- match flags (the "opt" column)
|
||||
if not ( match == true and (
|
||||
not args.flags or rule.flags == args.flags
|
||||
) ) then
|
||||
match = false
|
||||
end
|
||||
|
||||
-- match specific options
|
||||
if not ( match == true and (
|
||||
not args.options or
|
||||
self:_match_options( rule.options, args.options )
|
||||
) ) then
|
||||
match = false
|
||||
end
|
||||
|
||||
-- insert match
|
||||
if match == true then
|
||||
rv[#rv+1] = rule
|
||||
end
|
||||
end
|
||||
|
||||
return rv
|
||||
end
|
||||
|
||||
|
||||
-- through external commands.
|
||||
function IptParser.resync( self )
|
||||
self._rules = { }
|
||||
self._chain = nil
|
||||
self:_parse_rules()
|
||||
end
|
||||
|
||||
|
||||
function IptParser.tables( self )
|
||||
return self._tables
|
||||
end
|
||||
|
||||
|
||||
function IptParser.chains( self, table )
|
||||
local lookup = { }
|
||||
local chains = { }
|
||||
for _, r in ipairs(self:find({table=table})) do
|
||||
if not lookup[r.chain] then
|
||||
lookup[r.chain] = true
|
||||
chains[#chains+1] = r.chain
|
||||
end
|
||||
end
|
||||
return chains
|
||||
end
|
||||
|
||||
|
||||
-- and "rules". The "rules" field is a table of rule tables.
|
||||
function IptParser.chain( self, table, chain )
|
||||
return self._chains[table:lower()] and self._chains[table:lower()][chain]
|
||||
end
|
||||
|
||||
|
||||
function IptParser.is_custom_target( self, target )
|
||||
for _, r in ipairs(self._rules) do
|
||||
if r.chain == target then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
-- [internal] Parse address according to family.
|
||||
function IptParser._parse_addr( self, addr )
|
||||
if self._family == 4 then
|
||||
return luci.ip.IPv4(addr)
|
||||
else
|
||||
return luci.ip.IPv6(addr)
|
||||
end
|
||||
end
|
||||
|
||||
-- [internal] Parse iptables output from all tables.
|
||||
function IptParser._parse_rules( self )
|
||||
|
||||
for i, tbl in ipairs(self._tables) do
|
||||
|
||||
self._chains[tbl] = { }
|
||||
|
||||
for i, rule in ipairs(luci.util.execl(self._command % tbl)) do
|
||||
|
||||
if rule:find( "^Chain " ) == 1 then
|
||||
|
||||
local crefs
|
||||
local cname, cpol, cpkt, cbytes = rule:match(
|
||||
"^Chain ([^%s]*) %(policy (%w+) " ..
|
||||
"(%d+) packets, (%d+) bytes%)"
|
||||
)
|
||||
|
||||
if not cname then
|
||||
cname, crefs = rule:match(
|
||||
"^Chain ([^%s]*) %((%d+) references%)"
|
||||
)
|
||||
end
|
||||
|
||||
self._chain = cname
|
||||
self._chains[tbl][cname] = {
|
||||
policy = cpol,
|
||||
packets = tonumber(cpkt or 0),
|
||||
bytes = tonumber(cbytes or 0),
|
||||
references = tonumber(crefs or 0),
|
||||
rules = { }
|
||||
}
|
||||
|
||||
else
|
||||
if rule:find("%d") == 1 then
|
||||
|
||||
local rule_parts = luci.util.split( rule, "%s+", nil, true )
|
||||
local rule_details = { }
|
||||
|
||||
-- cope with rules that have no target assigned
|
||||
if rule:match("^%d+%s+%d+%s+%d+%s%s") then
|
||||
table.insert(rule_parts, 4, nil)
|
||||
end
|
||||
|
||||
-- ip6tables opt column is usually zero-width
|
||||
if self._family == 6 then
|
||||
table.insert(rule_parts, 6, "--")
|
||||
end
|
||||
|
||||
rule_details["table"] = tbl
|
||||
rule_details["chain"] = self._chain
|
||||
rule_details["index"] = tonumber(rule_parts[1])
|
||||
rule_details["packets"] = tonumber(rule_parts[2])
|
||||
rule_details["bytes"] = tonumber(rule_parts[3])
|
||||
rule_details["target"] = rule_parts[4]
|
||||
rule_details["protocol"] = rule_parts[5]
|
||||
rule_details["flags"] = rule_parts[6]
|
||||
rule_details["inputif"] = rule_parts[7]
|
||||
rule_details["outputif"] = rule_parts[8]
|
||||
rule_details["source"] = rule_parts[9]
|
||||
rule_details["destination"] = rule_parts[10]
|
||||
rule_details["options"] = { }
|
||||
|
||||
for i = 11, #rule_parts do
|
||||
if #rule_parts[i] > 0 then
|
||||
rule_details["options"][i-10] = rule_parts[i]
|
||||
end
|
||||
end
|
||||
|
||||
self._rules[#self._rules+1] = rule_details
|
||||
|
||||
self._chains[tbl][self._chain].rules[
|
||||
#self._chains[tbl][self._chain].rules + 1
|
||||
] = rule_details
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self._chain = nil
|
||||
end
|
||||
|
||||
|
||||
-- [internal] Return true if optlist1 contains all elements of optlist 2.
|
||||
-- Return false in all other cases.
|
||||
function IptParser._match_options( self, o1, o2 )
|
||||
|
||||
-- construct a hashtable of first options list to speed up lookups
|
||||
local oh = { }
|
||||
for i, opt in ipairs( o1 ) do oh[opt] = true end
|
||||
|
||||
-- iterate over second options list
|
||||
-- each string in o2 must be also present in o1
|
||||
-- if o2 contains a string which is not found in o1 then return false
|
||||
for i, opt in ipairs( o2 ) do
|
||||
if not oh[opt] then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return true
|
||||
end
|
|
@ -1,69 +0,0 @@
|
|||
---[[
|
||||
LuCI iptables parser and query library
|
||||
|
||||
@cstyle instance
|
||||
]]
|
||||
module "luci.sys.iptparser"
|
||||
|
||||
---[[
|
||||
Create a new iptables parser object.
|
||||
|
||||
@class function
|
||||
@name IptParser
|
||||
@param family Number specifying the address family. 4 for IPv4, 6 for IPv6
|
||||
@return IptParser instance
|
||||
]]
|
||||
|
||||
---[[
|
||||
Find all firewall rules that match the given criteria. Expects a table with
|
||||
|
||||
search criteria as only argument. If args is nil or an empty table then all
|
||||
rules will be returned.
|
||||
]]
|
||||
|
||||
---[[
|
||||
Rebuild the internal lookup table, for example when rules have changed
|
||||
|
||||
through external commands.
|
||||
@class function
|
||||
@name IptParser.resync
|
||||
@return nothing
|
||||
]]
|
||||
|
||||
---[[
|
||||
Find the names of all tables.
|
||||
|
||||
@class function
|
||||
@name IptParser.tables
|
||||
@return Table of table names.
|
||||
]]
|
||||
|
||||
---[[
|
||||
Find the names of all chains within the given table name.
|
||||
|
||||
@class function
|
||||
@name IptParser.chains
|
||||
@param table String containing the table name
|
||||
@return Table of chain names in the order they occur.
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return the given firewall chain within the given table name.
|
||||
|
||||
@class function
|
||||
@name IptParser.chain
|
||||
@param table String containing the table name
|
||||
@param chain String containing the chain name
|
||||
@return Table containing the fields "policy", "packets", "bytes"
|
||||
-- and "rules". The "rules" field is a table of rule tables.
|
||||
]]
|
||||
|
||||
---[[
|
||||
Test whether the given target points to a custom chain.
|
||||
|
||||
@class function
|
||||
@name IptParser.is_custom_target
|
||||
@param target String containing the target action
|
||||
@return Boolean indicating whether target is a custom chain.
|
||||
]]
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
local setmetatable, require, rawget, rawset = setmetatable, require, rawget, rawset
|
||||
|
||||
module "luci.sys.zoneinfo"
|
||||
|
||||
setmetatable(_M, {
|
||||
__index = function(t, k)
|
||||
if k == "TZ" and not rawget(t, k) then
|
||||
local m = require "luci.sys.zoneinfo.tzdata"
|
||||
rawset(t, k, rawget(m, k))
|
||||
elseif k == "OFFSET" and not rawget(t, k) then
|
||||
local m = require "luci.sys.zoneinfo.tzoffset"
|
||||
rawset(t, k, rawget(m, k))
|
||||
end
|
||||
|
||||
return rawget(t, k)
|
||||
end
|
||||
})
|
|
@ -1,457 +0,0 @@
|
|||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
module "luci.sys.zoneinfo.tzdata"
|
||||
|
||||
TZ = {
|
||||
{ 'Africa/Abidjan', 'GMT0' },
|
||||
{ 'Africa/Accra', 'GMT0' },
|
||||
{ 'Africa/Addis Ababa', 'EAT-3' },
|
||||
{ 'Africa/Algiers', 'CET-1' },
|
||||
{ 'Africa/Asmara', 'EAT-3' },
|
||||
{ 'Africa/Bamako', 'GMT0' },
|
||||
{ 'Africa/Bangui', 'WAT-1' },
|
||||
{ 'Africa/Banjul', 'GMT0' },
|
||||
{ 'Africa/Bissau', 'GMT0' },
|
||||
{ 'Africa/Blantyre', 'CAT-2' },
|
||||
{ 'Africa/Brazzaville', 'WAT-1' },
|
||||
{ 'Africa/Bujumbura', 'CAT-2' },
|
||||
{ 'Africa/Cairo', 'EET-2' },
|
||||
{ 'Africa/Casablanca', 'WET0WEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Africa/Ceuta', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Africa/Conakry', 'GMT0' },
|
||||
{ 'Africa/Dakar', 'GMT0' },
|
||||
{ 'Africa/Dar es Salaam', 'EAT-3' },
|
||||
{ 'Africa/Djibouti', 'EAT-3' },
|
||||
{ 'Africa/Douala', 'WAT-1' },
|
||||
{ 'Africa/El Aaiun', 'WET0WEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Africa/Freetown', 'GMT0' },
|
||||
{ 'Africa/Gaborone', 'CAT-2' },
|
||||
{ 'Africa/Harare', 'CAT-2' },
|
||||
{ 'Africa/Johannesburg', 'SAST-2' },
|
||||
{ 'Africa/Juba', 'EAT-3' },
|
||||
{ 'Africa/Kampala', 'EAT-3' },
|
||||
{ 'Africa/Khartoum', 'CAT-2' },
|
||||
{ 'Africa/Kigali', 'CAT-2' },
|
||||
{ 'Africa/Kinshasa', 'WAT-1' },
|
||||
{ 'Africa/Lagos', 'WAT-1' },
|
||||
{ 'Africa/Libreville', 'WAT-1' },
|
||||
{ 'Africa/Lome', 'GMT0' },
|
||||
{ 'Africa/Luanda', 'WAT-1' },
|
||||
{ 'Africa/Lubumbashi', 'CAT-2' },
|
||||
{ 'Africa/Lusaka', 'CAT-2' },
|
||||
{ 'Africa/Malabo', 'WAT-1' },
|
||||
{ 'Africa/Maputo', 'CAT-2' },
|
||||
{ 'Africa/Maseru', 'SAST-2' },
|
||||
{ 'Africa/Mbabane', 'SAST-2' },
|
||||
{ 'Africa/Mogadishu', 'EAT-3' },
|
||||
{ 'Africa/Monrovia', 'GMT0' },
|
||||
{ 'Africa/Nairobi', 'EAT-3' },
|
||||
{ 'Africa/Ndjamena', 'WAT-1' },
|
||||
{ 'Africa/Niamey', 'WAT-1' },
|
||||
{ 'Africa/Nouakchott', 'GMT0' },
|
||||
{ 'Africa/Ouagadougou', 'GMT0' },
|
||||
{ 'Africa/Porto-Novo', 'WAT-1' },
|
||||
{ 'Africa/Sao Tome', 'WAT-1' },
|
||||
{ 'Africa/Tripoli', 'EET-2' },
|
||||
{ 'Africa/Tunis', 'CET-1' },
|
||||
{ 'Africa/Windhoek', 'CAT-2' },
|
||||
{ 'America/Adak', 'HST10HDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Anchorage', 'AKST9AKDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Anguilla', 'AST4' },
|
||||
{ 'America/Antigua', 'AST4' },
|
||||
{ 'America/Araguaina', '<-03>3' },
|
||||
{ 'America/Argentina/Buenos Aires', '<-03>3' },
|
||||
{ 'America/Argentina/Catamarca', '<-03>3' },
|
||||
{ 'America/Argentina/Cordoba', '<-03>3' },
|
||||
{ 'America/Argentina/Jujuy', '<-03>3' },
|
||||
{ 'America/Argentina/La Rioja', '<-03>3' },
|
||||
{ 'America/Argentina/Mendoza', '<-03>3' },
|
||||
{ 'America/Argentina/Rio Gallegos', '<-03>3' },
|
||||
{ 'America/Argentina/Salta', '<-03>3' },
|
||||
{ 'America/Argentina/San Juan', '<-03>3' },
|
||||
{ 'America/Argentina/San Luis', '<-03>3' },
|
||||
{ 'America/Argentina/Tucuman', '<-03>3' },
|
||||
{ 'America/Argentina/Ushuaia', '<-03>3' },
|
||||
{ 'America/Aruba', 'AST4' },
|
||||
{ 'America/Asuncion', '<-04>4<-03>,M10.1.0/0,M3.4.0/0' },
|
||||
{ 'America/Atikokan', 'EST5' },
|
||||
{ 'America/Bahia', '<-03>3' },
|
||||
{ 'America/Bahia Banderas', 'CST6CDT,M4.1.0,M10.5.0' },
|
||||
{ 'America/Barbados', 'AST4' },
|
||||
{ 'America/Belem', '<-03>3' },
|
||||
{ 'America/Belize', 'CST6' },
|
||||
{ 'America/Blanc-Sablon', 'AST4' },
|
||||
{ 'America/Boa Vista', '<-04>4' },
|
||||
{ 'America/Bogota', '<-05>5' },
|
||||
{ 'America/Boise', 'MST7MDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Cambridge Bay', 'MST7MDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Campo Grande', '<-04>4<-03>,M11.1.0/0,M2.3.0/0' },
|
||||
{ 'America/Cancun', 'EST5' },
|
||||
{ 'America/Caracas', '<-04>4' },
|
||||
{ 'America/Cayenne', '<-03>3' },
|
||||
{ 'America/Cayman', 'EST5' },
|
||||
{ 'America/Chicago', 'CST6CDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Chihuahua', 'MST7MDT,M4.1.0,M10.5.0' },
|
||||
{ 'America/Costa Rica', 'CST6' },
|
||||
{ 'America/Creston', 'MST7' },
|
||||
{ 'America/Cuiaba', '<-04>4<-03>,M11.1.0/0,M2.3.0/0' },
|
||||
{ 'America/Curacao', 'AST4' },
|
||||
{ 'America/Danmarkshavn', 'GMT0' },
|
||||
{ 'America/Dawson', 'PST8PDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Dawson Creek', 'MST7' },
|
||||
{ 'America/Denver', 'MST7MDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Detroit', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Dominica', 'AST4' },
|
||||
{ 'America/Edmonton', 'MST7MDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Eirunepe', '<-05>5' },
|
||||
{ 'America/El Salvador', 'CST6' },
|
||||
{ 'America/Fort Nelson', 'MST7' },
|
||||
{ 'America/Fortaleza', '<-03>3' },
|
||||
{ 'America/Glace Bay', 'AST4ADT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Godthab', '<-03>3<-02>,M3.5.0/-2,M10.5.0/-1' },
|
||||
{ 'America/Goose Bay', 'AST4ADT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Grand Turk', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Grenada', 'AST4' },
|
||||
{ 'America/Guadeloupe', 'AST4' },
|
||||
{ 'America/Guatemala', 'CST6' },
|
||||
{ 'America/Guayaquil', '<-05>5' },
|
||||
{ 'America/Guyana', '<-04>4' },
|
||||
{ 'America/Halifax', 'AST4ADT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Havana', 'CST5CDT,M3.2.0/0,M11.1.0/1' },
|
||||
{ 'America/Hermosillo', 'MST7' },
|
||||
{ 'America/Indiana/Indianapolis', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Indiana/Knox', 'CST6CDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Indiana/Marengo', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Indiana/Petersburg', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Indiana/Tell City', 'CST6CDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Indiana/Vevay', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Indiana/Vincennes', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Indiana/Winamac', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Inuvik', 'MST7MDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Iqaluit', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Jamaica', 'EST5' },
|
||||
{ 'America/Juneau', 'AKST9AKDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Kentucky/Louisville', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Kentucky/Monticello', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Kralendijk', 'AST4' },
|
||||
{ 'America/La Paz', '<-04>4' },
|
||||
{ 'America/Lima', '<-05>5' },
|
||||
{ 'America/Los Angeles', 'PST8PDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Lower Princes', 'AST4' },
|
||||
{ 'America/Maceio', '<-03>3' },
|
||||
{ 'America/Managua', 'CST6' },
|
||||
{ 'America/Manaus', '<-04>4' },
|
||||
{ 'America/Marigot', 'AST4' },
|
||||
{ 'America/Martinique', 'AST4' },
|
||||
{ 'America/Matamoros', 'CST6CDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Mazatlan', 'MST7MDT,M4.1.0,M10.5.0' },
|
||||
{ 'America/Menominee', 'CST6CDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Merida', 'CST6CDT,M4.1.0,M10.5.0' },
|
||||
{ 'America/Metlakatla', 'AKST9AKDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Mexico City', 'CST6CDT,M4.1.0,M10.5.0' },
|
||||
{ 'America/Miquelon', '<-03>3<-02>,M3.2.0,M11.1.0' },
|
||||
{ 'America/Moncton', 'AST4ADT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Monterrey', 'CST6CDT,M4.1.0,M10.5.0' },
|
||||
{ 'America/Montevideo', '<-03>3' },
|
||||
{ 'America/Montserrat', 'AST4' },
|
||||
{ 'America/Nassau', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/New York', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Nipigon', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Nome', 'AKST9AKDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Noronha', '<-02>2' },
|
||||
{ 'America/North Dakota/Beulah', 'CST6CDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/North Dakota/Center', 'CST6CDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/North Dakota/New Salem', 'CST6CDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Ojinaga', 'MST7MDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Panama', 'EST5' },
|
||||
{ 'America/Pangnirtung', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Paramaribo', '<-03>3' },
|
||||
{ 'America/Phoenix', 'MST7' },
|
||||
{ 'America/Port of Spain', 'AST4' },
|
||||
{ 'America/Port-au-Prince', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Porto Velho', '<-04>4' },
|
||||
{ 'America/Puerto Rico', 'AST4' },
|
||||
{ 'America/Punta Arenas', '<-03>3' },
|
||||
{ 'America/Rainy River', 'CST6CDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Rankin Inlet', 'CST6CDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Recife', '<-03>3' },
|
||||
{ 'America/Regina', 'CST6' },
|
||||
{ 'America/Resolute', 'CST6CDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Rio Branco', '<-05>5' },
|
||||
{ 'America/Santarem', '<-03>3' },
|
||||
{ 'America/Santiago', '<-04>4<-03>,M8.2.6/24,M5.2.6/24' },
|
||||
{ 'America/Santo Domingo', 'AST4' },
|
||||
{ 'America/Sao Paulo', '<-03>3<-02>,M11.1.0/0,M2.3.0/0' },
|
||||
{ 'America/Scoresbysund', '<-01>1<+00>,M3.5.0/0,M10.5.0/1' },
|
||||
{ 'America/Sitka', 'AKST9AKDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/St Barthelemy', 'AST4' },
|
||||
{ 'America/St Johns', 'NST3:30NDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/St Kitts', 'AST4' },
|
||||
{ 'America/St Lucia', 'AST4' },
|
||||
{ 'America/St Thomas', 'AST4' },
|
||||
{ 'America/St Vincent', 'AST4' },
|
||||
{ 'America/Swift Current', 'CST6' },
|
||||
{ 'America/Tegucigalpa', 'CST6' },
|
||||
{ 'America/Thule', 'AST4ADT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Thunder Bay', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Tijuana', 'PST8PDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Toronto', 'EST5EDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Tortola', 'AST4' },
|
||||
{ 'America/Vancouver', 'PST8PDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Whitehorse', 'PST8PDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Winnipeg', 'CST6CDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Yakutat', 'AKST9AKDT,M3.2.0,M11.1.0' },
|
||||
{ 'America/Yellowknife', 'MST7MDT,M3.2.0,M11.1.0' },
|
||||
{ 'Antarctica/Casey', '<+08>-8' },
|
||||
{ 'Antarctica/Davis', '<+07>-7' },
|
||||
{ 'Antarctica/DumontDUrville', '<+10>-10' },
|
||||
{ 'Antarctica/Macquarie', '<+11>-11' },
|
||||
{ 'Antarctica/Mawson', '<+05>-5' },
|
||||
{ 'Antarctica/McMurdo', 'NZST-12NZDT,M9.5.0,M4.1.0/3' },
|
||||
{ 'Antarctica/Palmer', '<-03>3' },
|
||||
{ 'Antarctica/Rothera', '<-03>3' },
|
||||
{ 'Antarctica/Syowa', '<+03>-3' },
|
||||
{ 'Antarctica/Troll', '<+00>0<+02>-2,M3.5.0/1,M10.5.0/3' },
|
||||
{ 'Antarctica/Vostok', '<+06>-6' },
|
||||
{ 'Arctic/Longyearbyen', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Asia/Aden', '<+03>-3' },
|
||||
{ 'Asia/Almaty', '<+06>-6' },
|
||||
{ 'Asia/Amman', 'EET-2EEST,M3.5.4/24,M10.5.5/1' },
|
||||
{ 'Asia/Anadyr', '<+12>-12' },
|
||||
{ 'Asia/Aqtau', '<+05>-5' },
|
||||
{ 'Asia/Aqtobe', '<+05>-5' },
|
||||
{ 'Asia/Ashgabat', '<+05>-5' },
|
||||
{ 'Asia/Atyrau', '<+05>-5' },
|
||||
{ 'Asia/Baghdad', '<+03>-3' },
|
||||
{ 'Asia/Bahrain', '<+03>-3' },
|
||||
{ 'Asia/Baku', '<+04>-4' },
|
||||
{ 'Asia/Bangkok', '<+07>-7' },
|
||||
{ 'Asia/Barnaul', '<+07>-7' },
|
||||
{ 'Asia/Beirut', 'EET-2EEST,M3.5.0/0,M10.5.0/0' },
|
||||
{ 'Asia/Bishkek', '<+06>-6' },
|
||||
{ 'Asia/Brunei', '<+08>-8' },
|
||||
{ 'Asia/Chita', '<+09>-9' },
|
||||
{ 'Asia/Choibalsan', '<+08>-8' },
|
||||
{ 'Asia/Colombo', '<+0530>-5:30' },
|
||||
{ 'Asia/Damascus', 'EET-2EEST,M3.5.5/0,M10.5.5/0' },
|
||||
{ 'Asia/Dhaka', '<+06>-6' },
|
||||
{ 'Asia/Dili', '<+09>-9' },
|
||||
{ 'Asia/Dubai', '<+04>-4' },
|
||||
{ 'Asia/Dushanbe', '<+05>-5' },
|
||||
{ 'Asia/Famagusta', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Asia/Gaza', 'EET-2EEST,M3.4.6/1,M10.5.6/1' },
|
||||
{ 'Asia/Hebron', 'EET-2EEST,M3.4.6/1,M10.5.6/1' },
|
||||
{ 'Asia/Ho Chi Minh', '<+07>-7' },
|
||||
{ 'Asia/Hong Kong', 'HKT-8' },
|
||||
{ 'Asia/Hovd', '<+07>-7' },
|
||||
{ 'Asia/Irkutsk', '<+08>-8' },
|
||||
{ 'Asia/Jakarta', 'WIB-7' },
|
||||
{ 'Asia/Jayapura', 'WIT-9' },
|
||||
{ 'Asia/Jerusalem', 'IST-2IDT,M3.4.4/26,M10.5.0' },
|
||||
{ 'Asia/Kabul', '<+0430>-4:30' },
|
||||
{ 'Asia/Kamchatka', '<+12>-12' },
|
||||
{ 'Asia/Karachi', 'PKT-5' },
|
||||
{ 'Asia/Kathmandu', '<+0545>-5:45' },
|
||||
{ 'Asia/Khandyga', '<+09>-9' },
|
||||
{ 'Asia/Kolkata', 'IST-5:30' },
|
||||
{ 'Asia/Krasnoyarsk', '<+07>-7' },
|
||||
{ 'Asia/Kuala Lumpur', '<+08>-8' },
|
||||
{ 'Asia/Kuching', '<+08>-8' },
|
||||
{ 'Asia/Kuwait', '<+03>-3' },
|
||||
{ 'Asia/Macau', 'CST-8' },
|
||||
{ 'Asia/Magadan', '<+11>-11' },
|
||||
{ 'Asia/Makassar', 'WITA-8' },
|
||||
{ 'Asia/Manila', '<+08>-8' },
|
||||
{ 'Asia/Muscat', '<+04>-4' },
|
||||
{ 'Asia/Nicosia', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Asia/Novokuznetsk', '<+07>-7' },
|
||||
{ 'Asia/Novosibirsk', '<+07>-7' },
|
||||
{ 'Asia/Omsk', '<+06>-6' },
|
||||
{ 'Asia/Oral', '<+05>-5' },
|
||||
{ 'Asia/Phnom Penh', '<+07>-7' },
|
||||
{ 'Asia/Pontianak', 'WIB-7' },
|
||||
{ 'Asia/Pyongyang', 'KST-8:30' },
|
||||
{ 'Asia/Qatar', '<+03>-3' },
|
||||
{ 'Asia/Qyzylorda', '<+06>-6' },
|
||||
{ 'Asia/Riyadh', '<+03>-3' },
|
||||
{ 'Asia/Sakhalin', '<+11>-11' },
|
||||
{ 'Asia/Samarkand', '<+05>-5' },
|
||||
{ 'Asia/Seoul', 'KST-9' },
|
||||
{ 'Asia/Shanghai', 'CST-8' },
|
||||
{ 'Asia/Singapore', '<+08>-8' },
|
||||
{ 'Asia/Srednekolymsk', '<+11>-11' },
|
||||
{ 'Asia/Taipei', 'CST-8' },
|
||||
{ 'Asia/Tashkent', '<+05>-5' },
|
||||
{ 'Asia/Tbilisi', '<+04>-4' },
|
||||
{ 'Asia/Tehran', '<+0330>-3:30<+0430>,J80/0,J264/0' },
|
||||
{ 'Asia/Thimphu', '<+06>-6' },
|
||||
{ 'Asia/Tokyo', 'JST-9' },
|
||||
{ 'Asia/Tomsk', '<+07>-7' },
|
||||
{ 'Asia/Ulaanbaatar', '<+08>-8' },
|
||||
{ 'Asia/Urumqi', '<+06>-6' },
|
||||
{ 'Asia/Ust-Nera', '<+10>-10' },
|
||||
{ 'Asia/Vientiane', '<+07>-7' },
|
||||
{ 'Asia/Vladivostok', '<+10>-10' },
|
||||
{ 'Asia/Yakutsk', '<+09>-9' },
|
||||
{ 'Asia/Yangon', '<+0630>-6:30' },
|
||||
{ 'Asia/Yekaterinburg', '<+05>-5' },
|
||||
{ 'Asia/Yerevan', '<+04>-4' },
|
||||
{ 'Atlantic/Azores', '<-01>1<+00>,M3.5.0/0,M10.5.0/1' },
|
||||
{ 'Atlantic/Bermuda', 'AST4ADT,M3.2.0,M11.1.0' },
|
||||
{ 'Atlantic/Canary', 'WET0WEST,M3.5.0/1,M10.5.0' },
|
||||
{ 'Atlantic/Cape Verde', '<-01>1' },
|
||||
{ 'Atlantic/Faroe', 'WET0WEST,M3.5.0/1,M10.5.0' },
|
||||
{ 'Atlantic/Madeira', 'WET0WEST,M3.5.0/1,M10.5.0' },
|
||||
{ 'Atlantic/Reykjavik', 'GMT0' },
|
||||
{ 'Atlantic/South Georgia', '<-02>2' },
|
||||
{ 'Atlantic/St Helena', 'GMT0' },
|
||||
{ 'Atlantic/Stanley', '<-03>3' },
|
||||
{ 'Australia/Adelaide', 'ACST-9:30ACDT,M10.1.0,M4.1.0/3' },
|
||||
{ 'Australia/Brisbane', 'AEST-10' },
|
||||
{ 'Australia/Broken Hill', 'ACST-9:30ACDT,M10.1.0,M4.1.0/3' },
|
||||
{ 'Australia/Currie', 'AEST-10AEDT,M10.1.0,M4.1.0/3' },
|
||||
{ 'Australia/Darwin', 'ACST-9:30' },
|
||||
{ 'Australia/Eucla', '<+0845>-8:45' },
|
||||
{ 'Australia/Hobart', 'AEST-10AEDT,M10.1.0,M4.1.0/3' },
|
||||
{ 'Australia/Lindeman', 'AEST-10' },
|
||||
{ 'Australia/Lord Howe', '<+1030>-10:30<+11>-11,M10.1.0,M4.1.0' },
|
||||
{ 'Australia/Melbourne', 'AEST-10AEDT,M10.1.0,M4.1.0/3' },
|
||||
{ 'Australia/Perth', 'AWST-8' },
|
||||
{ 'Australia/Sydney', 'AEST-10AEDT,M10.1.0,M4.1.0/3' },
|
||||
{ 'Etc/GMT', 'GMT0' },
|
||||
{ 'Etc/GMT+1', '<-01>1' },
|
||||
{ 'Etc/GMT+10', '<-10>10' },
|
||||
{ 'Etc/GMT+11', '<-11>11' },
|
||||
{ 'Etc/GMT+12', '<-12>12' },
|
||||
{ 'Etc/GMT+2', '<-02>2' },
|
||||
{ 'Etc/GMT+3', '<-03>3' },
|
||||
{ 'Etc/GMT+4', '<-04>4' },
|
||||
{ 'Etc/GMT+5', '<-05>5' },
|
||||
{ 'Etc/GMT+6', '<-06>6' },
|
||||
{ 'Etc/GMT+7', '<-07>7' },
|
||||
{ 'Etc/GMT+8', '<-08>8' },
|
||||
{ 'Etc/GMT+9', '<-09>9' },
|
||||
{ 'Etc/GMT-1', '<+01>-1' },
|
||||
{ 'Etc/GMT-10', '<+10>-10' },
|
||||
{ 'Etc/GMT-11', '<+11>-11' },
|
||||
{ 'Etc/GMT-12', '<+12>-12' },
|
||||
{ 'Etc/GMT-13', '<+13>-13' },
|
||||
{ 'Etc/GMT-14', '<+14>-14' },
|
||||
{ 'Etc/GMT-2', '<+02>-2' },
|
||||
{ 'Etc/GMT-3', '<+03>-3' },
|
||||
{ 'Etc/GMT-4', '<+04>-4' },
|
||||
{ 'Etc/GMT-5', '<+05>-5' },
|
||||
{ 'Etc/GMT-6', '<+06>-6' },
|
||||
{ 'Etc/GMT-7', '<+07>-7' },
|
||||
{ 'Etc/GMT-8', '<+08>-8' },
|
||||
{ 'Etc/GMT-9', '<+09>-9' },
|
||||
{ 'Europe/Amsterdam', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Andorra', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Astrakhan', '<+04>-4' },
|
||||
{ 'Europe/Athens', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Europe/Belgrade', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Berlin', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Bratislava', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Brussels', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Bucharest', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Europe/Budapest', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Busingen', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Chisinau', 'EET-2EEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Copenhagen', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Dublin', 'GMT0IST,M3.5.0/1,M10.5.0' },
|
||||
{ 'Europe/Gibraltar', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Guernsey', 'GMT0BST,M3.5.0/1,M10.5.0' },
|
||||
{ 'Europe/Helsinki', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Europe/Isle of Man', 'GMT0BST,M3.5.0/1,M10.5.0' },
|
||||
{ 'Europe/Istanbul', '<+03>-3' },
|
||||
{ 'Europe/Jersey', 'GMT0BST,M3.5.0/1,M10.5.0' },
|
||||
{ 'Europe/Kaliningrad', 'EET-2' },
|
||||
{ 'Europe/Kiev', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Europe/Kirov', '<+03>-3' },
|
||||
{ 'Europe/Lisbon', 'WET0WEST,M3.5.0/1,M10.5.0' },
|
||||
{ 'Europe/Ljubljana', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/London', 'GMT0BST,M3.5.0/1,M10.5.0' },
|
||||
{ 'Europe/Luxembourg', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Madrid', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Malta', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Mariehamn', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Europe/Minsk', '<+03>-3' },
|
||||
{ 'Europe/Monaco', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Moscow', 'MSK-3' },
|
||||
{ 'Europe/Oslo', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Paris', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Podgorica', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Prague', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Riga', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Europe/Rome', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Samara', '<+04>-4' },
|
||||
{ 'Europe/San Marino', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Sarajevo', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Saratov', '<+04>-4' },
|
||||
{ 'Europe/Simferopol', 'MSK-3' },
|
||||
{ 'Europe/Skopje', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Sofia', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Europe/Stockholm', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Tallinn', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Europe/Tirane', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Ulyanovsk', '<+04>-4' },
|
||||
{ 'Europe/Uzhgorod', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Europe/Vaduz', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Vatican', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Vienna', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Vilnius', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Europe/Volgograd', '<+03>-3' },
|
||||
{ 'Europe/Warsaw', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Zagreb', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Europe/Zaporozhye', 'EET-2EEST,M3.5.0/3,M10.5.0/4' },
|
||||
{ 'Europe/Zurich', 'CET-1CEST,M3.5.0,M10.5.0/3' },
|
||||
{ 'Indian/Antananarivo', 'EAT-3' },
|
||||
{ 'Indian/Chagos', '<+06>-6' },
|
||||
{ 'Indian/Christmas', '<+07>-7' },
|
||||
{ 'Indian/Cocos', '<+0630>-6:30' },
|
||||
{ 'Indian/Comoro', 'EAT-3' },
|
||||
{ 'Indian/Kerguelen', '<+05>-5' },
|
||||
{ 'Indian/Mahe', '<+04>-4' },
|
||||
{ 'Indian/Maldives', '<+05>-5' },
|
||||
{ 'Indian/Mauritius', '<+04>-4' },
|
||||
{ 'Indian/Mayotte', 'EAT-3' },
|
||||
{ 'Indian/Reunion', '<+04>-4' },
|
||||
{ 'Pacific/Apia', '<+13>-13<+14>,M9.5.0/3,M4.1.0/4' },
|
||||
{ 'Pacific/Auckland', 'NZST-12NZDT,M9.5.0,M4.1.0/3' },
|
||||
{ 'Pacific/Bougainville', '<+11>-11' },
|
||||
{ 'Pacific/Chatham', '<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45' },
|
||||
{ 'Pacific/Chuuk', '<+10>-10' },
|
||||
{ 'Pacific/Easter', '<-06>6<-05>,M8.2.6/22,M5.2.6/22' },
|
||||
{ 'Pacific/Efate', '<+11>-11' },
|
||||
{ 'Pacific/Enderbury', '<+13>-13' },
|
||||
{ 'Pacific/Fakaofo', '<+13>-13' },
|
||||
{ 'Pacific/Fiji', '<+12>-12<+13>,M11.1.0,M1.2.1/147' },
|
||||
{ 'Pacific/Funafuti', '<+12>-12' },
|
||||
{ 'Pacific/Galapagos', '<-06>6' },
|
||||
{ 'Pacific/Gambier', '<-09>9' },
|
||||
{ 'Pacific/Guadalcanal', '<+11>-11' },
|
||||
{ 'Pacific/Guam', 'ChST-10' },
|
||||
{ 'Pacific/Honolulu', 'HST10' },
|
||||
{ 'Pacific/Kiritimati', '<+14>-14' },
|
||||
{ 'Pacific/Kosrae', '<+11>-11' },
|
||||
{ 'Pacific/Kwajalein', '<+12>-12' },
|
||||
{ 'Pacific/Majuro', '<+12>-12' },
|
||||
{ 'Pacific/Marquesas', '<-0930>9:30' },
|
||||
{ 'Pacific/Midway', 'SST11' },
|
||||
{ 'Pacific/Nauru', '<+12>-12' },
|
||||
{ 'Pacific/Niue', '<-11>11' },
|
||||
{ 'Pacific/Norfolk', '<+11>-11' },
|
||||
{ 'Pacific/Noumea', '<+11>-11' },
|
||||
{ 'Pacific/Pago Pago', 'SST11' },
|
||||
{ 'Pacific/Palau', '<+09>-9' },
|
||||
{ 'Pacific/Pitcairn', '<-08>8' },
|
||||
{ 'Pacific/Pohnpei', '<+11>-11' },
|
||||
{ 'Pacific/Port Moresby', '<+10>-10' },
|
||||
{ 'Pacific/Rarotonga', '<-10>10' },
|
||||
{ 'Pacific/Saipan', 'ChST-10' },
|
||||
{ 'Pacific/Tahiti', '<-10>10' },
|
||||
{ 'Pacific/Tarawa', '<+12>-12' },
|
||||
{ 'Pacific/Tongatapu', '<+13>-13' },
|
||||
{ 'Pacific/Wake', '<+12>-12' },
|
||||
{ 'Pacific/Wallis', '<+12>-12' },
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
module "luci.sys.zoneinfo.tzoffset"
|
||||
|
||||
OFFSET = {
|
||||
gmt = 0, -- GMT
|
||||
eat = 10800, -- EAT
|
||||
cet = 3600, -- CET
|
||||
wat = 3600, -- WAT
|
||||
cat = 7200, -- CAT
|
||||
eet = 7200, -- EET
|
||||
wet = 0, -- WET
|
||||
sast = 7200, -- SAST
|
||||
hst = -36000, -- HST
|
||||
hdt = -32400, -- HDT
|
||||
akst = -32400, -- AKST
|
||||
akdt = -28800, -- AKDT
|
||||
ast = -14400, -- AST
|
||||
est = -18000, -- EST
|
||||
cst = -21600, -- CST
|
||||
cdt = -18000, -- CDT
|
||||
mst = -25200, -- MST
|
||||
mdt = -21600, -- MDT
|
||||
pst = -28800, -- PST
|
||||
pdt = -25200, -- PDT
|
||||
nst = -12600, -- NST
|
||||
ndt = -9000, -- NDT
|
||||
nzst = 43200, -- NZST
|
||||
nzdt = 46800, -- NZDT
|
||||
hkt = 28800, -- HKT
|
||||
wib = 25200, -- WIB
|
||||
wit = 32400, -- WIT
|
||||
ist = 7200, -- IST
|
||||
idt = 10800, -- IDT
|
||||
pkt = 18000, -- PKT
|
||||
wita = 28800, -- WITA
|
||||
kst = 30600, -- KST
|
||||
jst = 32400, -- JST
|
||||
acst = 34200, -- ACST
|
||||
acdt = 37800, -- ACDT
|
||||
aest = 36000, -- AEST
|
||||
awst = 28800, -- AWST
|
||||
msk = 10800, -- MSK
|
||||
sst = -39600, -- SST
|
||||
}
|
|
@ -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 '" .. 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 occured: " .. tostring(err or "(nil)"))
|
||||
end
|
||||
end
|
|
@ -1,36 +0,0 @@
|
|||
-- Copyright 2012 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
module("luci.tools.proto", package.seeall)
|
||||
|
||||
function opt_macaddr(s, ifc, ...)
|
||||
local v = luci.cbi.Value
|
||||
local o = s:taboption("advanced", v, "macaddr", ...)
|
||||
|
||||
o.placeholder = ifc and ifc:mac()
|
||||
o.datatype = "macaddr"
|
||||
|
||||
function o.cfgvalue(self, section)
|
||||
local w = ifc and ifc:get_wifinet()
|
||||
if w then
|
||||
return w:get("macaddr")
|
||||
else
|
||||
return v.cfgvalue(self, section)
|
||||
end
|
||||
end
|
||||
|
||||
function o.write(self, section, value)
|
||||
local w = ifc and ifc:get_wifinet()
|
||||
if w then
|
||||
w:set("macaddr", value)
|
||||
elseif value then
|
||||
v.write(self, section, value)
|
||||
else
|
||||
v.remove(self, section)
|
||||
end
|
||||
end
|
||||
|
||||
function o.remove(self, section)
|
||||
self:write(section, nil)
|
||||
end
|
||||
end
|
|
@ -1,305 +0,0 @@
|
|||
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
|
||||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
module("luci.tools.status", package.seeall)
|
||||
|
||||
local uci = require "luci.model.uci".cursor()
|
||||
local ipc = require "luci.ip"
|
||||
|
||||
local function duid_to_mac(duid)
|
||||
local b1, b2, b3, b4, b5, b6
|
||||
|
||||
-- DUID-LLT / Ethernet
|
||||
if type(duid) == "string" and #duid == 28 then
|
||||
b1, b2, b3, b4, b5, b6 = duid:match("^00010001(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)%x%x%x%x%x%x%x%x$")
|
||||
|
||||
-- DUID-LL / Ethernet
|
||||
elseif type(duid) == "string" and #duid == 20 then
|
||||
b1, b2, b3, b4, b5, b6 = duid:match("^00030001(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)$")
|
||||
end
|
||||
|
||||
return b1 and ipc.checkmac(table.concat({ b1, b2, b3, b4, b5, b6 }, ":"))
|
||||
end
|
||||
|
||||
local function dhcp_leases_common(family)
|
||||
local rv = { }
|
||||
local nfs = require "nixio.fs"
|
||||
local sys = require "luci.sys"
|
||||
local leasefile = "/tmp/dhcp.leases"
|
||||
|
||||
uci:foreach("dhcp", "dnsmasq",
|
||||
function(s)
|
||||
if s.leasefile and nfs.access(s.leasefile) then
|
||||
leasefile = s.leasefile
|
||||
return false
|
||||
end
|
||||
end)
|
||||
|
||||
local fd = io.open(leasefile, "r")
|
||||
if fd then
|
||||
while true do
|
||||
local ln = fd:read("*l")
|
||||
if not ln then
|
||||
break
|
||||
else
|
||||
local ts, mac, ip, name, duid = ln:match("^(%d+) (%S+) (%S+) (%S+) (%S+)")
|
||||
local expire = tonumber(ts) or 0
|
||||
if ts and mac and ip and name and duid then
|
||||
if family == 4 and not ip:match(":") then
|
||||
rv[#rv+1] = {
|
||||
expires = (expire ~= 0) and os.difftime(expire, os.time()),
|
||||
macaddr = ipc.checkmac(mac) or "00:00:00:00:00:00",
|
||||
ipaddr = ip,
|
||||
hostname = (name ~= "*") and name
|
||||
}
|
||||
elseif family == 6 and ip:match(":") then
|
||||
rv[#rv+1] = {
|
||||
expires = (expire ~= 0) and os.difftime(expire, os.time()),
|
||||
ip6addr = ip,
|
||||
duid = (duid ~= "*") and duid,
|
||||
hostname = (name ~= "*") and name
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
fd:close()
|
||||
end
|
||||
|
||||
local lease6file = "/tmp/hosts/odhcpd"
|
||||
uci:foreach("dhcp", "odhcpd",
|
||||
function(t)
|
||||
if t.leasefile and nfs.access(t.leasefile) then
|
||||
lease6file = t.leasefile
|
||||
return false
|
||||
end
|
||||
end)
|
||||
local fd = io.open(lease6file, "r")
|
||||
if fd then
|
||||
while true do
|
||||
local ln = fd:read("*l")
|
||||
if not ln then
|
||||
break
|
||||
else
|
||||
local iface, duid, iaid, name, ts, id, length, ip = ln:match("^# (%S+) (%S+) (%S+) (%S+) (-?%d+) (%S+) (%S+) (.*)")
|
||||
local expire = tonumber(ts) or 0
|
||||
if ip and iaid ~= "ipv4" and family == 6 then
|
||||
rv[#rv+1] = {
|
||||
expires = (expire >= 0) and os.difftime(expire, os.time()),
|
||||
duid = duid,
|
||||
ip6addr = ip,
|
||||
hostname = (name ~= "-") and name
|
||||
}
|
||||
elseif ip and iaid == "ipv4" and family == 4 then
|
||||
rv[#rv+1] = {
|
||||
expires = (expire >= 0) and os.difftime(expire, os.time()),
|
||||
macaddr = ipc.checkmac(duid:gsub("^(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)(%x%x)$", "%1:%2:%3:%4:%5:%6")) or "00:00:00:00:00:00",
|
||||
ipaddr = ip,
|
||||
hostname = (name ~= "-") and name
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
fd:close()
|
||||
end
|
||||
|
||||
if family == 6 then
|
||||
local _, lease
|
||||
local hosts = sys.net.host_hints()
|
||||
for _, lease in ipairs(rv) do
|
||||
local mac = duid_to_mac(lease.duid)
|
||||
local host = mac and hosts[mac]
|
||||
if host then
|
||||
if not lease.name then
|
||||
lease.host_hint = host.name or host.ipv4 or host.ipv6
|
||||
elseif host.name and lease.hostname ~= host.name then
|
||||
lease.host_hint = host.name
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return rv
|
||||
end
|
||||
|
||||
function dhcp_leases()
|
||||
return dhcp_leases_common(4)
|
||||
end
|
||||
|
||||
function dhcp6_leases()
|
||||
return dhcp_leases_common(6)
|
||||
end
|
||||
|
||||
function wifi_networks()
|
||||
local rv = { }
|
||||
local ntm = require "luci.model.network".init()
|
||||
|
||||
local dev
|
||||
for _, dev in ipairs(ntm:get_wifidevs()) do
|
||||
local rd = {
|
||||
up = dev:is_up(),
|
||||
device = dev:name(),
|
||||
name = dev:get_i18n(),
|
||||
networks = { }
|
||||
}
|
||||
|
||||
local net
|
||||
for _, net in ipairs(dev:get_wifinets()) do
|
||||
local a, an = nil, 0
|
||||
for _, a in pairs(net:assoclist() or {}) do
|
||||
an = an + 1
|
||||
end
|
||||
|
||||
rd.networks[#rd.networks+1] = {
|
||||
name = net:shortname(),
|
||||
link = net:adminlink(),
|
||||
up = net:is_up(),
|
||||
mode = net:active_mode(),
|
||||
ssid = net:active_ssid(),
|
||||
bssid = net:active_bssid(),
|
||||
encryption = net:active_encryption(),
|
||||
frequency = net:frequency(),
|
||||
channel = net:channel(),
|
||||
signal = net:signal(),
|
||||
quality = net:signal_percent(),
|
||||
noise = net:noise(),
|
||||
bitrate = net:bitrate(),
|
||||
ifname = net:ifname(),
|
||||
country = net:country(),
|
||||
txpower = net:txpower(),
|
||||
txpoweroff = net:txpower_offset(),
|
||||
num_assoc = an,
|
||||
disabled = (dev:get("disabled") == "1" or
|
||||
net:get("disabled") == "1")
|
||||
}
|
||||
end
|
||||
|
||||
rv[#rv+1] = rd
|
||||
end
|
||||
|
||||
return rv
|
||||
end
|
||||
|
||||
function wifi_network(id)
|
||||
local ntm = require "luci.model.network".init()
|
||||
local net = ntm:get_wifinet(id)
|
||||
if net then
|
||||
local dev = net:get_device()
|
||||
if dev then
|
||||
return {
|
||||
id = id,
|
||||
name = net:shortname(),
|
||||
link = net:adminlink(),
|
||||
up = net:is_up(),
|
||||
mode = net:active_mode(),
|
||||
ssid = net:active_ssid(),
|
||||
bssid = net:active_bssid(),
|
||||
encryption = net:active_encryption(),
|
||||
frequency = net:frequency(),
|
||||
channel = net:channel(),
|
||||
signal = net:signal(),
|
||||
quality = net:signal_percent(),
|
||||
noise = net:noise(),
|
||||
bitrate = net:bitrate(),
|
||||
ifname = net:ifname(),
|
||||
country = net:country(),
|
||||
txpower = net:txpower(),
|
||||
txpoweroff = net:txpower_offset(),
|
||||
disabled = (dev:get("disabled") == "1" or
|
||||
net:get("disabled") == "1"),
|
||||
device = {
|
||||
up = dev:is_up(),
|
||||
device = dev:name(),
|
||||
name = dev:get_i18n()
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
return { }
|
||||
end
|
||||
|
||||
function wifi_assoclist()
|
||||
local sys = require "luci.sys"
|
||||
local ntm = require "luci.model.network".init()
|
||||
local hosts = sys.net.host_hints()
|
||||
|
||||
local assoc = {}
|
||||
local _, dev, net, bss
|
||||
|
||||
for _, dev in ipairs(ntm:get_wifidevs()) do
|
||||
local radioname = dev:get_i18n()
|
||||
|
||||
for _, net in ipairs(dev:get_wifinets()) do
|
||||
local netname = net:shortname()
|
||||
local netlink = net:adminlink()
|
||||
local ifname = net:ifname()
|
||||
|
||||
for _, bss in pairs(net:assoclist() or {}) do
|
||||
local host = hosts[_]
|
||||
|
||||
bss.bssid = _
|
||||
bss.ifname = ifname
|
||||
bss.radio = radioname
|
||||
bss.name = netname
|
||||
bss.link = netlink
|
||||
|
||||
bss.host_name = (host) and (host.name or host.ipv4 or host.ipv6)
|
||||
bss.host_hint = (host and host.name and (host.ipv4 or host.ipv6)) and (host.ipv4 or host.ipv6)
|
||||
|
||||
assoc[#assoc+1] = bss
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
table.sort(assoc, function(a, b)
|
||||
if a.radio ~= b.radio then
|
||||
return a.radio < b.radio
|
||||
elseif a.ifname ~= b.ifname then
|
||||
return a.ifname < b.ifname
|
||||
else
|
||||
return a.bssid < b.bssid
|
||||
end
|
||||
end)
|
||||
|
||||
return assoc
|
||||
end
|
||||
|
||||
function switch_status(devs)
|
||||
local dev
|
||||
local switches = { }
|
||||
for dev in devs:gmatch("[^%s,]+") do
|
||||
local ports = { }
|
||||
local swc = io.popen("swconfig dev %s show"
|
||||
% luci.util.shellquote(dev), "r")
|
||||
|
||||
if swc then
|
||||
local l
|
||||
repeat
|
||||
l = swc:read("*l")
|
||||
if l then
|
||||
local port, up = l:match("port:(%d+) link:(%w+)")
|
||||
if port then
|
||||
local speed = l:match(" speed:(%d+)")
|
||||
local duplex = l:match(" (%w+)-duplex")
|
||||
local txflow = l:match(" (txflow)")
|
||||
local rxflow = l:match(" (rxflow)")
|
||||
local auto = l:match(" (auto)")
|
||||
|
||||
ports[#ports+1] = {
|
||||
port = tonumber(port) or 0,
|
||||
speed = tonumber(speed) or 0,
|
||||
link = (up == "up"),
|
||||
duplex = (duplex == "full"),
|
||||
rxflow = (not not rxflow),
|
||||
txflow = (not not txflow),
|
||||
auto = (not not auto)
|
||||
}
|
||||
end
|
||||
end
|
||||
until not l
|
||||
swc:close()
|
||||
end
|
||||
switches[dev] = ports
|
||||
end
|
||||
return switches
|
||||
end
|
|
@ -1,105 +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.
|
||||
|
||||
module("luci.tools.webadmin", package.seeall)
|
||||
|
||||
local util = require "luci.util"
|
||||
local uci = require "luci.model.uci"
|
||||
local ip = require "luci.ip"
|
||||
|
||||
function byte_format(byte)
|
||||
local suff = {"B", "KB", "MB", "GB", "TB"}
|
||||
for i=1, 5 do
|
||||
if byte > 1024 and i < 5 then
|
||||
byte = byte / 1024
|
||||
else
|
||||
return string.format("%.2f %s", byte, suff[i])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function date_format(secs)
|
||||
local suff = {"min", "h", "d"}
|
||||
local mins = 0
|
||||
local hour = 0
|
||||
local days = 0
|
||||
|
||||
secs = math.floor(secs)
|
||||
if secs > 60 then
|
||||
mins = math.floor(secs / 60)
|
||||
secs = secs % 60
|
||||
end
|
||||
|
||||
if mins > 60 then
|
||||
hour = math.floor(mins / 60)
|
||||
mins = mins % 60
|
||||
end
|
||||
|
||||
if hour > 24 then
|
||||
days = math.floor(hour / 24)
|
||||
hour = hour % 24
|
||||
end
|
||||
|
||||
if days > 0 then
|
||||
return string.format("%.0fd %02.0fh %02.0fmin %02.0fs", days, hour, mins, secs)
|
||||
else
|
||||
return string.format("%02.0fh %02.0fmin %02.0fs", hour, mins, secs)
|
||||
end
|
||||
end
|
||||
|
||||
function cbi_add_networks(field)
|
||||
uci.cursor():foreach("network", "interface",
|
||||
function (section)
|
||||
if section[".name"] ~= "loopback" then
|
||||
field:value(section[".name"])
|
||||
end
|
||||
end
|
||||
)
|
||||
field.titleref = luci.dispatcher.build_url("admin", "network", "network")
|
||||
end
|
||||
|
||||
function cbi_add_knownips(field)
|
||||
local _, n
|
||||
for _, n in ipairs(ip.neighbors({ family = 4 })) do
|
||||
if n.dest then
|
||||
field:value(n.dest:string())
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function firewall_find_zone(name)
|
||||
local find
|
||||
|
||||
luci.model.uci.cursor():foreach("firewall", "zone",
|
||||
function (section)
|
||||
if section.name == name then
|
||||
find = section[".name"]
|
||||
end
|
||||
end
|
||||
)
|
||||
|
||||
return find
|
||||
end
|
||||
|
||||
function iface_get_network(iface)
|
||||
local link = ip.link(tostring(iface))
|
||||
if link.master then
|
||||
iface = link.master
|
||||
end
|
||||
|
||||
local cur = uci.cursor()
|
||||
local dump = util.ubus("network.interface", "dump", { })
|
||||
if dump then
|
||||
local _, net
|
||||
for _, net in ipairs(dump.interface) do
|
||||
if net.l3_device == iface or net.device == iface then
|
||||
-- cross check with uci to filter out @name style aliases
|
||||
local uciname = cur:get("network", net.interface, "ifname")
|
||||
if type(uciname) == "string" and uciname:sub(1,1) ~= "@" or uciname then
|
||||
return net.interface
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,777 +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
|
||||
|
||||
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)
|
||||
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)
|
||||
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
|
||||
--
|
||||
|
||||
function pcdata(value)
|
||||
return value and tparser.pcdata(tostring(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
|
||||
|
||||
function striptags(value)
|
||||
return value and tparser.striptags(tostring(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, "^\-", "\\-")
|
||||
res, _ = string.gsub(res, "^-", "\-")
|
||||
return shellsqescape(value)
|
||||
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 interator 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.pcdata = pcdata
|
||||
string.striptags = striptags
|
||||
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)
|
||||
if not _ubus_connection then
|
||||
_ubus_connection = _ubus.connect()
|
||||
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
|
|
@ -1,413 +0,0 @@
|
|||
---[[
|
||||
LuCI utility functions.
|
||||
]]
|
||||
module "luci.util"
|
||||
|
||||
---[[
|
||||
Create a Class object (Python-style object model).
|
||||
|
||||
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.
|
||||
|
||||
@class function
|
||||
@name class
|
||||
@param base The base class to inherit from (optional)
|
||||
@return A class object
|
||||
@see instanceof
|
||||
@see clone
|
||||
]]
|
||||
|
||||
---[[
|
||||
Test whether the given object is an instance of the given class.
|
||||
|
||||
@class function
|
||||
@name instanceof
|
||||
@param object Object instance
|
||||
@param class Class object to test against
|
||||
@return Boolean indicating whether the object is an instance
|
||||
@see class
|
||||
@see clone
|
||||
]]
|
||||
|
||||
---[[
|
||||
Create a new or get an already existing thread local store associated with
|
||||
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.
|
||||
|
||||
@class function
|
||||
@name threadlocal
|
||||
@return Table value representing the corresponding thread local store
|
||||
]]
|
||||
|
||||
---[[
|
||||
Write given object to stderr.
|
||||
|
||||
@class function
|
||||
@name perror
|
||||
@param obj Value to write to stderr
|
||||
@return Boolean indicating whether the write operation was successful
|
||||
]]
|
||||
|
||||
---[[
|
||||
Recursively dumps a table to stdout, useful for testing and debugging.
|
||||
|
||||
@class function
|
||||
@name dumptable
|
||||
@param t Table value to dump
|
||||
@param maxdepth Maximum depth
|
||||
@return Always nil
|
||||
]]
|
||||
|
||||
---[[
|
||||
Create valid XML PCDATA from given string.
|
||||
|
||||
@class function
|
||||
@name pcdata
|
||||
@param value String value containing the data to escape
|
||||
@return String value containing the escaped data
|
||||
]]
|
||||
|
||||
---[[
|
||||
Decode an URL-encoded string - optionally decoding the "+" sign to space.
|
||||
|
||||
@class function
|
||||
@name urldecode
|
||||
@param str Input string in x-www-urlencoded format
|
||||
@param decode_plus Decode "+" signs to spaces if true (optional)
|
||||
@return The decoded string
|
||||
@see urlencode
|
||||
]]
|
||||
|
||||
---[[
|
||||
URL-encode given string.
|
||||
|
||||
@class function
|
||||
@name urlencode
|
||||
@param str String to encode
|
||||
@return String containing the encoded data
|
||||
@see urldecode
|
||||
]]
|
||||
|
||||
---[[
|
||||
Strip HTML tags from given string.
|
||||
|
||||
@class function
|
||||
@name striptags
|
||||
@param value String containing the HTML text
|
||||
@return String with HTML tags stripped of
|
||||
]]
|
||||
|
||||
---[[
|
||||
Safely quote value for use in shell commands.
|
||||
|
||||
@class function
|
||||
@name shellquote
|
||||
@param value String containing the value to quote
|
||||
@return Single-quote enclosed string with embedded quotes escaped
|
||||
]]
|
||||
|
||||
---[[
|
||||
Splits given string on a defined separator sequence and return a table
|
||||
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
|
||||
nterpreted as regular expression.
|
||||
|
||||
@class function
|
||||
@name split
|
||||
@param str String value containing the data to split up
|
||||
@param pat String with separator pattern (optional, defaults to "\n")
|
||||
@param max Maximum times to split (optional)
|
||||
@param regex Boolean indicating whether to interpret the separator
|
||||
-- pattern as regular expression (optional, default is false)
|
||||
@return Table containing the resulting substrings
|
||||
]]
|
||||
|
||||
---[[
|
||||
Remove leading and trailing whitespace from given string value.
|
||||
|
||||
@class function
|
||||
@name trim
|
||||
@param str String value containing whitespace padded data
|
||||
@return String value with leading and trailing space removed
|
||||
]]
|
||||
|
||||
---[[
|
||||
Count the occurrences of given substring in given string.
|
||||
|
||||
@class function
|
||||
@name cmatch
|
||||
@param str String to search in
|
||||
@param pattern String containing pattern to find
|
||||
@return Number of found occurrences
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return a matching iterator for the given value.
|
||||
|
||||
The iterator will return 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 interator which aborts with the first invocation.
|
||||
|
||||
@class function
|
||||
@name imatch
|
||||
@param val The value to scan (table, string or nil)
|
||||
@return Iterator which returns one token per call
|
||||
]]
|
||||
|
||||
---[[
|
||||
Parse certain units from the given string and return the canonical integer
|
||||
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)
|
||||
|
||||
@class function
|
||||
@name parse_units
|
||||
@param ustr String containing a numerical value with trailing unit
|
||||
@return Number containing the canonical value
|
||||
]]
|
||||
|
||||
---[[
|
||||
Appends numerically indexed tables or single objects to a given table.
|
||||
|
||||
@class function
|
||||
@name append
|
||||
@param src Target table
|
||||
@param ... Objects to insert
|
||||
@return Target table
|
||||
]]
|
||||
|
||||
---[[
|
||||
Combines two or more numerically indexed tables and single objects into one table.
|
||||
|
||||
@class function
|
||||
@name combine
|
||||
@param tbl1 Table value to combine
|
||||
@param tbl2 Table value to combine
|
||||
@param ... More tables to combine
|
||||
@return Table value containing all values of given tables
|
||||
]]
|
||||
|
||||
---[[
|
||||
Checks whether the given table contains the given value.
|
||||
|
||||
@class function
|
||||
@name contains
|
||||
@param table Table value
|
||||
@param value Value to search within the given table
|
||||
@return Number indicating the first index at which the given value occurs
|
||||
-- within table or false.
|
||||
]]
|
||||
|
||||
---[[
|
||||
Update values in given table with the values from the second given table.
|
||||
|
||||
Both table are - in fact - merged together.
|
||||
|
||||
@class function
|
||||
@name update
|
||||
@param t Table which should be updated
|
||||
@param updates Table containing the values to update
|
||||
@return Always nil
|
||||
]]
|
||||
|
||||
---[[
|
||||
Retrieve all keys of given associative table.
|
||||
|
||||
@class function
|
||||
@name keys
|
||||
@param t Table to extract keys from
|
||||
@return Sorted table containing the keys
|
||||
]]
|
||||
|
||||
---[[
|
||||
Clones the given object and return it's copy.
|
||||
|
||||
@class function
|
||||
@name clone
|
||||
@param object Table value to clone
|
||||
@param deep Boolean indicating whether to do recursive cloning
|
||||
@return Cloned table value
|
||||
]]
|
||||
|
||||
---[[
|
||||
Recursively serialize given data to lua code, suitable for restoring
|
||||
with loadstring().
|
||||
|
||||
@class function
|
||||
@name serialize_data
|
||||
@param val Value containing the data to serialize
|
||||
@return String value containing the serialized code
|
||||
@see restore_data
|
||||
@see get_bytecode
|
||||
]]
|
||||
|
||||
---[[
|
||||
Restore data previously serialized with serialize_data().
|
||||
|
||||
@class function
|
||||
@name restore_data
|
||||
@param str String containing the data to restore
|
||||
@return Value containing the restored data structure
|
||||
@see serialize_data
|
||||
@see get_bytecode
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return the current runtime bytecode of the given data. The byte code
|
||||
will be stripped before it is returned.
|
||||
|
||||
@class function
|
||||
@name get_bytecode
|
||||
@param val Value to return as bytecode
|
||||
@return String value containing the bytecode of the given data
|
||||
]]
|
||||
|
||||
---[[
|
||||
Strips unnescessary lua bytecode from given string.
|
||||
|
||||
Information like line numbers and debugging numbers will be discarded.
|
||||
Original version by Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html)
|
||||
|
||||
@class function
|
||||
@name strip_bytecode
|
||||
@param code String value containing the original lua byte code
|
||||
@return String value containing the stripped lua byte code
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return a key, value iterator which returns the values sorted according to
|
||||
the provided callback function.
|
||||
|
||||
@class function
|
||||
@name spairs
|
||||
@param t The table to iterate
|
||||
@param f A callback function to decide the order of elements
|
||||
@return Function value containing the corresponding iterator
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return a key, value iterator for the given table.
|
||||
|
||||
The table pairs are sorted by key.
|
||||
|
||||
@class function
|
||||
@name kspairs
|
||||
@param t The table to iterate
|
||||
@return Function value containing the corresponding iterator
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return a key, value iterator for the given table.
|
||||
|
||||
The table pairs are sorted by value.
|
||||
|
||||
@class function
|
||||
@name vspairs
|
||||
@param t The table to iterate
|
||||
@return Function value containing the corresponding iterator
|
||||
]]
|
||||
|
||||
---[[
|
||||
Test whether the current system is operating in big endian mode.
|
||||
|
||||
@class function
|
||||
@name bigendian
|
||||
@return Boolean value indicating whether system is big endian
|
||||
]]
|
||||
|
||||
---[[
|
||||
Execute given commandline and gather stdout.
|
||||
|
||||
@class function
|
||||
@name exec
|
||||
@param command String containing command to execute
|
||||
@return String containing the command's stdout
|
||||
]]
|
||||
|
||||
---[[
|
||||
Return a line-buffered iterator over the output of given command.
|
||||
|
||||
@class function
|
||||
@name execi
|
||||
@param command String containing the command to execute
|
||||
@return Iterator
|
||||
]]
|
||||
|
||||
---[[
|
||||
Issue an ubus call.
|
||||
|
||||
@class function
|
||||
@name ubus
|
||||
@param object String containing the ubus object to call
|
||||
@param method String containing the ubus method to call
|
||||
@param values Table containing the values to pass
|
||||
@return Table containin the ubus result
|
||||
]]
|
||||
|
||||
---[[
|
||||
Convert data structure to JSON
|
||||
|
||||
@class function
|
||||
@name serialize_json
|
||||
@param data The data to serialize
|
||||
@param writer A function to write a chunk of JSON data (optional)
|
||||
@return String containing the JSON if called without write callback
|
||||
]]
|
||||
|
||||
---[[
|
||||
Returns the absolute path to LuCI base directory.
|
||||
|
||||
@class function
|
||||
@name libpath
|
||||
@return String containing the directory path
|
||||
]]
|
||||
|
||||
---[[
|
||||
This is a coroutine-safe drop-in replacement for Lua's "xpcall"-function
|
||||
|
||||
@class function
|
||||
@name coxpcall
|
||||
@param f Lua function to be called protected
|
||||
@param err Custom error handler
|
||||
@param ... Parameters passed to the function
|
||||
@return A boolean whether the function call succeeded and the return
|
||||
-- values of either the function or the error handler
|
||||
]]
|
||||
|
||||
---[[
|
||||
This is a coroutine-safe drop-in replacement for Lua's "pcall"-function
|
||||
|
||||
@class function
|
||||
@name copcall
|
||||
@param f Lua function to be called protected
|
||||
@param ... Parameters passed to the function
|
||||
@return A boolean whether the function call succeeded and the returns
|
||||
-- values of the function or the error object
|
||||
]]
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
-- Licensed to the public under the Apache License 2.0.
|
||||
|
||||
module "luci.version"
|
||||
|
||||
distname = "Host System"
|
||||
distversion = "SDK"
|
||||
|
||||
luciname = "LuCI"
|
||||
luciversion = "SVN"
|
|
@ -1,228 +0,0 @@
|
|||
<% export("cbi_apply_widget", function(redirect_ok, rollback_token) -%>
|
||||
<style type="text/css">
|
||||
#cbi_apply_overlay {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
display: none;
|
||||
z-index: 20000;
|
||||
}
|
||||
|
||||
#cbi_apply_overlay .alert-message {
|
||||
position: relative;
|
||||
top: 10%;
|
||||
width: 60%;
|
||||
margin: auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
min-height: 32px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#cbi_apply_overlay .alert-message > h4,
|
||||
#cbi_apply_overlay .alert-message > p,
|
||||
#cbi_apply_overlay .alert-message > div {
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
#cbi_apply_overlay .alert-message > img {
|
||||
margin-right: 1em;
|
||||
flex-basis: 32px;
|
||||
}
|
||||
|
||||
body.apply-overlay-active {
|
||||
overflow: hidden;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
body.apply-overlay-active #cbi_apply_overlay {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript" src="<%=resource%>/cbi.js?v=git-18.138.59467-72fe5dd"></script>
|
||||
<script type="text/javascript">//<![CDATA[
|
||||
var xhr = new XHR(),
|
||||
uci_apply_auth = { sid: '<%=luci.dispatcher.context.authsession%>', token: '<%=token%>' },
|
||||
uci_apply_rollback = <%=math.max(luci.config and luci.config.apply and luci.config.apply.rollback or 30, 30)%>,
|
||||
uci_apply_holdoff = <%=math.max(luci.config and luci.config.apply and luci.config.apply.holdoff or 4, 1)%>,
|
||||
uci_apply_timeout = <%=math.max(luci.config and luci.config.apply and luci.config.apply.timeout or 5, 1)%>,
|
||||
uci_apply_display = <%=math.max(luci.config and luci.config.apply and luci.config.apply.display or 1.5, 1)%>,
|
||||
uci_confirm_auth = <% if rollback_token then %>{ token: '<%=rollback_token%>' }<% else %>null<% end %>,
|
||||
was_xhr_poll_running = false;
|
||||
|
||||
function uci_status_message(type, content) {
|
||||
var overlay = document.getElementById('cbi_apply_overlay') || document.body.appendChild(E('<div id="cbi_apply_overlay"><div class="alert-message"></div></div>')),
|
||||
message = overlay.querySelector('.alert-message');
|
||||
|
||||
if (message && type) {
|
||||
if (!message.classList.contains(type)) {
|
||||
message.classList.remove('notice');
|
||||
message.classList.remove('warning');
|
||||
message.classList.add(type);
|
||||
}
|
||||
|
||||
if (content)
|
||||
message.innerHTML = content;
|
||||
|
||||
document.body.classList.add('apply-overlay-active');
|
||||
|
||||
if (!was_xhr_poll_running) {
|
||||
was_xhr_poll_running = XHR.running();
|
||||
XHR.halt();
|
||||
}
|
||||
}
|
||||
else {
|
||||
document.body.classList.remove('apply-overlay-active');
|
||||
|
||||
if (was_xhr_poll_running)
|
||||
XHR.run();
|
||||
}
|
||||
}
|
||||
|
||||
function uci_rollback(checked) {
|
||||
if (checked) {
|
||||
uci_status_message('warning',
|
||||
'<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
|
||||
'<%:Failed to confirm apply within %ds, waiting for rollback…%>'.format(uci_apply_rollback));
|
||||
|
||||
var call = function(r, data, duration) {
|
||||
if (r.status === 204) {
|
||||
uci_status_message('warning',
|
||||
'<h4><%:Configuration has been rolled back!%></h4>' +
|
||||
'<p><%:The device could not be reached within %d seconds after applying the pending changes, which caused the configuration to be rolled back for safety reasons. If you believe that the configuration changes are correct nonetheless, perform an unchecked configuration apply. Alternatively, you can dismiss this warning and edit changes before attempting to apply again, or revert all pending changes to keep the currently working configuration state.%></p>'.format(uci_apply_rollback) +
|
||||
'<div class="right">' +
|
||||
'<input type="button" class="btn" onclick="uci_status_message(false)" value="<%:Dismiss%>" /> ' +
|
||||
'<input type="button" class="btn cbi-button-action important" onclick="uci_revert()" value="<%:Revert changes%>" /> ' +
|
||||
'<input type="button" class="btn cbi-button-negative important" onclick="uci_apply(false)" value="<%:Apply unchecked%>" />' +
|
||||
'</div>');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var delay = isNaN(duration) ? 0 : Math.max(1000 - duration, 0);
|
||||
window.setTimeout(function() {
|
||||
xhr.post('<%=url("admin/uci/confirm")%>', uci_apply_auth, call, uci_apply_timeout * 1000);
|
||||
}, delay);
|
||||
};
|
||||
|
||||
call({ status: 0 });
|
||||
}
|
||||
else {
|
||||
uci_status_message('warning',
|
||||
'<h4><%:Device unreachable!%></h4>' +
|
||||
'<p><%:Could not regain access to the device after applying the configuration changes. You might need to reconnect if you modified network related settings such as the IP address or wireless security credentials.%></p>');
|
||||
}
|
||||
}
|
||||
|
||||
function uci_confirm(checked, deadline) {
|
||||
var tt;
|
||||
var ts = Date.now();
|
||||
|
||||
uci_status_message('notice');
|
||||
|
||||
var call = function(r, data, duration) {
|
||||
if (Date.now() >= deadline) {
|
||||
uci_rollback(checked);
|
||||
return;
|
||||
}
|
||||
else if (r && (r.status === 200 || r.status === 204)) {
|
||||
var indicator = document.querySelector('.uci_change_indicator');
|
||||
if (indicator) indicator.style.display = 'none';
|
||||
|
||||
uci_status_message('notice', '<%:Configuration has been applied.%>');
|
||||
|
||||
window.clearTimeout(tt);
|
||||
window.setTimeout(function() {
|
||||
<% if redirect_ok then -%>
|
||||
location.href = decodeURIComponent('<%=luci.util.urlencode(redirect_ok)%>');
|
||||
<%- else -%>
|
||||
window.location = window.location.href.split('#')[0];
|
||||
<% end %>
|
||||
}, uci_apply_display * 1000);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var delay = isNaN(duration) ? 0 : Math.max(1000 - duration, 0);
|
||||
window.setTimeout(function() {
|
||||
xhr.post('<%=url("admin/uci/confirm")%>', uci_confirm_auth, call, uci_apply_timeout * 1000);
|
||||
}, delay);
|
||||
};
|
||||
|
||||
var tick = function() {
|
||||
var now = Date.now();
|
||||
|
||||
uci_status_message('notice',
|
||||
'<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
|
||||
'<%:Waiting for configuration to get applied… %ds%>'.format(Math.max(Math.floor((deadline - Date.now()) / 1000), 0)));
|
||||
|
||||
if (now >= deadline)
|
||||
return;
|
||||
|
||||
tt = window.setTimeout(tick, 1000 - (now - ts));
|
||||
ts = now;
|
||||
};
|
||||
|
||||
tick();
|
||||
|
||||
/* wait a few seconds for the settings to become effective */
|
||||
window.setTimeout(call, Math.max(uci_apply_holdoff * 1000 - ((ts + uci_apply_rollback * 1000) - deadline), 1));
|
||||
}
|
||||
|
||||
function uci_apply(checked) {
|
||||
uci_status_message('notice',
|
||||
'<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
|
||||
'<%:Starting configuration apply…%>');
|
||||
|
||||
xhr.post('<%=url("admin/uci")%>/' + (checked ? 'apply_rollback' : 'apply_unchecked'), uci_apply_auth, function(r, tok) {
|
||||
if (r.status === (checked ? 200 : 204)) {
|
||||
if (checked && tok !== null && typeof(tok) === 'object' && typeof(tok.token) === 'string')
|
||||
uci_confirm_auth = tok;
|
||||
|
||||
uci_confirm(checked, Date.now() + uci_apply_rollback * 1000);
|
||||
}
|
||||
else if (checked && r.status === 204) {
|
||||
uci_status_message('notice', '<%:There are no changes to apply.%>');
|
||||
window.setTimeout(function() {
|
||||
<% if redirect_ok then -%>
|
||||
location.href = decodeURIComponent('<%=luci.util.urlencode(redirect_ok)%>');
|
||||
<%- else -%>
|
||||
uci_status_message(false);
|
||||
<%- end %>
|
||||
}, uci_apply_display * 1000);
|
||||
}
|
||||
else {
|
||||
uci_status_message('warning', '<%_Apply request failed with status <code>%h</code>%>'.format(r.responseText || r.statusText || r.status));
|
||||
window.setTimeout(function() { uci_status_message(false); }, uci_apply_display * 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function uci_revert() {
|
||||
uci_status_message('notice',
|
||||
'<img src="<%=resource%>/icons/loading.gif" alt="" style="vertical-align:middle" /> ' +
|
||||
'<%:Reverting configuration…%>');
|
||||
|
||||
xhr.post('<%=url("admin/uci/revert")%>', uci_apply_auth, function(r) {
|
||||
if (r.status === 200) {
|
||||
uci_status_message('notice', '<%:Changes have been reverted.%>');
|
||||
window.setTimeout(function() {
|
||||
<% if redirect_ok then -%>
|
||||
location.href = decodeURIComponent('<%=luci.util.urlencode(redirect_ok)%>');
|
||||
<%- else -%>
|
||||
window.location = window.location.href.split('#')[0];
|
||||
<%- end %>
|
||||
}, uci_apply_display * 1000);
|
||||
}
|
||||
else {
|
||||
uci_status_message('warning', '<%_Revert request failed with status <code>%h</code>%>'.format(r.statusText || r.status));
|
||||
window.setTimeout(function() { uci_status_message(false); }, uci_apply_display * 1000);
|
||||
}
|
||||
});
|
||||
}
|
||||
//]]></script>
|
||||
<%- end) %>
|
|
@ -1,8 +0,0 @@
|
|||
<% local v = self:cfgvalue(section) -%>
|
||||
<%+cbi/valueheader%>
|
||||
<input class="cbi-input-text" type="text"<%= attr("value", v) .. attr("name", cbid) .. attr("id", cbid) %> />
|
||||
<script type="text/javascript">
|
||||
cbi_init()
|
||||
cbi_browser_init('<%=cbid%>', '<%=resource%>', '<%=url('admin/filebrowser')%>'<%=self.default_path and ", '"..self.default_path.."'"%>);
|
||||
</script>
|
||||
<%+cbi/valuefooter%>
|
|
@ -1,7 +0,0 @@
|
|||
<%+cbi/valueheader%>
|
||||
<% if self:cfgvalue(section) ~= false then %>
|
||||
<input class="cbi-button cbi-button-<%=self.inputstyle or "button" %>" type="submit"<%= attr("name", cbid) .. attr("id", cbid) .. attr("value", self.inputtitle or self.title)%> />
|
||||
<% else %>
|
||||
-
|
||||
<% end %>
|
||||
<%+cbi/valuefooter%>
|
|
@ -1,2 +0,0 @@
|
|||
</div>
|
||||
</div>
|
|
@ -1,12 +0,0 @@
|
|||
<%-
|
||||
local title = luci.util.trim(striptags(self.title))
|
||||
local descr = luci.util.trim(striptags(self.description))
|
||||
local ftype = self.typename or (self.template and self.template:gsub("^.+/", ""))
|
||||
-%>
|
||||
<div class="td cbi-value-field<% if self.error and self.error[section] then %> cbi-value-error<% end %>"<%=
|
||||
attr("data-name", self.option) ..
|
||||
ifattr(ftype and #ftype > 0, "data-type", ftype) ..
|
||||
ifattr(title and #title > 0, "data-title", title) ..
|
||||
ifattr(descr and #descr > 0, "data-description", descr)
|
||||
%>>
|
||||
<div id="cbi-<%=self.config.."-"..section.."-"..self.option%>" data-index="<%=self.index%>" data-depends="<%=pcdata(self:deplist2json(section))%>">
|
|
@ -1 +0,0 @@
|
|||
<%- self:render_children() %>
|
|
@ -1,24 +0,0 @@
|
|||
<%- self.active:render() %>
|
||||
<div class="cbi-page-actions">
|
||||
<input type="hidden" name="cbi.delg.current" value="<%=self.current%>" />
|
||||
<% for _, x in ipairs(self.chain) do %>
|
||||
<input type="hidden" name="cbi.delg.path" value="<%=x%>" />
|
||||
<% end %>
|
||||
<% if not self.disallow_pageactions then %>
|
||||
<% if self.allow_finish and not self:get_next(self.current) then %>
|
||||
<input class="cbi-button cbi-button-finish" type="submit" value="<%:Finish%>" />
|
||||
<% elseif self:get_next(self.current) then %>
|
||||
<input class="cbi-button cbi-button-next" type="submit" value="<%:Next »%>" />
|
||||
<% end %>
|
||||
<% if self.allow_cancel then %>
|
||||
<input class="cbi-button cbi-button-cancel" type="submit" name="cbi.cancel" value="<%:Cancel%>" />
|
||||
<% end %>
|
||||
<% if self.allow_reset then %>
|
||||
<input class="cbi-button cbi-button-reset" type="reset" value="<%:Reset%>" />
|
||||
<% end %>
|
||||
<% if self.allow_back and self:get_prev(self.current) then %>
|
||||
<input class="cbi-button cbi-button-back" type="submit" name="cbi.delg.back" value="<%:« Back%>" />
|
||||
<% end %>
|
||||
<% end %>
|
||||
<script type="text/javascript">cbi_d_update();</script>
|
||||
</div>
|
|
@ -1,54 +0,0 @@
|
|||
<%+cbi/valueheader%>
|
||||
|
||||
<%-
|
||||
local selected = { }
|
||||
|
||||
if self.multiple then
|
||||
local val
|
||||
for val in luci.util.imatch(self:cfgvalue(section)) do
|
||||
selected[val] = true
|
||||
end
|
||||
else
|
||||
selected[self:cfgvalue(section)] = true
|
||||
end
|
||||
|
||||
if not next(selected) and self.default then
|
||||
selected[self.default] = true
|
||||
end
|
||||
-%>
|
||||
|
||||
<div class="cbi-dropdown"<%=
|
||||
attr("name", cbid) ..
|
||||
attr("display-items", self.display or self.size or 3) ..
|
||||
attr("dropdown-items", self.dropdown or self.display or self.size or 5) ..
|
||||
attr("placeholder", self.placeholder or translate("-- please select --")) ..
|
||||
ifattr(self.multiple, "multiple", "multiple") ..
|
||||
ifattr(self.optional or self.rmempty, "optional", "optional")
|
||||
%>>
|
||||
<ul>
|
||||
<% local i, key; for i, key in pairs(self.keylist) do %>
|
||||
<li<%=
|
||||
attr("data-index", i) ..
|
||||
attr("data-depends", self:deplist2json(section, self.deplist[i])) ..
|
||||
attr("value", key) ..
|
||||
ifattr(selected[key], "selected", "selected")
|
||||
%>>
|
||||
<%=pcdata(self.vallist[i])%>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if self.custom then %>
|
||||
<li>
|
||||
<input type="password" style="display:none" />
|
||||
<input class="create-item-input" type="text"<%=
|
||||
attr("placeholder", self.custom ~= true and
|
||||
self.custom or
|
||||
(self.multiple and
|
||||
translate("Enter custom values") or
|
||||
translate("Enter custom value")))
|
||||
%> />
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<%+cbi/valuefooter%>
|
|
@ -1,13 +0,0 @@
|
|||
<%+cbi/valueheader%>
|
||||
<% if self.href then %><a href="<%=self.href%>"><% end -%>
|
||||
<%
|
||||
local val = self:cfgvalue(section) or self.default or ""
|
||||
if not self.rawhtml then
|
||||
write(pcdata(val))
|
||||
else
|
||||
write(val)
|
||||
end
|
||||
%>
|
||||
<%- if self.href then %></a><%end%>
|
||||
<input type="hidden" id="<%=cbid%>" value="<%=pcdata(self:cfgvalue(section) or self.default or "")%>" />
|
||||
<%+cbi/valuefooter%>
|
|
@ -1,27 +0,0 @@
|
|||
<%+cbi/valueheader%>
|
||||
<div<%=
|
||||
attr("data-prefix", cbid) ..
|
||||
attr("data-browser-path", self.default_path) ..
|
||||
attr("data-dynlist", luci.util.serialize_json({
|
||||
self.keylist, self.vallist,
|
||||
self.datatype, self.optional or self.rmempty
|
||||
})) ..
|
||||
|
||||
ifattr(self.size, "data-size", self.size) ..
|
||||
ifattr(self.placeholder, "data-placeholder", self.placeholder)
|
||||
%>>
|
||||
<%
|
||||
local vals = self:cfgvalue(section) or {}
|
||||
for i=1, #vals + 1 do
|
||||
local val = vals[i]
|
||||
if (val and #val > 0) or (i == 1) then
|
||||
%>
|
||||
<input class="cbi-input-text" value="<%=pcdata(val)%>" data-update="change" type="text"<%=
|
||||
attr("id", cbid .. "." .. i) ..
|
||||
attr("name", cbid) ..
|
||||
ifattr(self.size, "size") ..
|
||||
ifattr(i == 1 and self.placeholder, "placeholder", self.placeholder)
|
||||
%> /><br />
|
||||
<% end end %>
|
||||
</div>
|
||||
<%+cbi/valuefooter%>
|
|
@ -1,19 +0,0 @@
|
|||
<div class="cbi-map" id="cbi-<%=self.config%>">
|
||||
<% if self.title and #self.title > 0 then %><h2 name="content"><%=self.title%></h2><% end %>
|
||||
<% if self.description and #self.description > 0 then %><div class="cbi-map-descr"><%=self.description%></div><% end %>
|
||||
|
||||
<p class="alert-message danger">
|
||||
<%: The configuration file could not be loaded due to the following error: %><br />
|
||||
<code><%=pcdata(self.error)%></code>
|
||||
</p>
|
||||
|
||||
<textarea name="cbi.source" style="width:100%; margin-bottom:1em" rows="<%=math.max(self.source:cmatch("\n"), 10)%>"><%=pcdata(self.source)%></textarea>
|
||||
|
||||
<p class="alert-message">
|
||||
<%: Edit the raw configuration data above to fix any error and hit "Save" to reload the page. %>
|
||||
</p>
|
||||
|
||||
<div class="cbi-page-actions">
|
||||
<input class="cbi-button cbi-button-apply" type="submit" name="cbi.save" value="<%:Save%>" />
|
||||
</div>
|
||||
</div>
|
|
@ -1,113 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
||||
<head>
|
||||
<title>Filebrowser - LuCI</title>
|
||||
<style type="text/css">
|
||||
#path, #listing {
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
ul {
|
||||
padding-left: 0;
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
li img {
|
||||
vertical-align: bottom;
|
||||
margin-right: 0.2em;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript">
|
||||
function callback(path) {
|
||||
if( window.opener ) {
|
||||
var input = window.opener.document.getElementById(decodeURIComponent('<%=luci.http.urlencode(luci.http.formvalue('field'))%>'));
|
||||
if( input ) {
|
||||
input.value = decodeURIComponent(path);
|
||||
window.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<%
|
||||
require("nixio.fs")
|
||||
require("nixio.util")
|
||||
require("luci.http")
|
||||
require("luci.dispatcher")
|
||||
|
||||
local field = luci.http.formvalue('field')
|
||||
local request = luci.dispatcher.context.args
|
||||
local path = { '' }
|
||||
|
||||
for i = 1, #request do
|
||||
if request[i] ~= '..' and #request[i] > 0 then
|
||||
path[#path+1] = request[i]
|
||||
end
|
||||
end
|
||||
|
||||
local filestat = nixio.fs.stat(table.concat(path, '/'))
|
||||
local baseurl = { 'admin', 'filebrowser' }
|
||||
|
||||
if filestat and filestat.type == "reg" then
|
||||
path[#path] = ''
|
||||
elseif not (filestat and filestat.type == "dir") then
|
||||
path = { '', '' }
|
||||
else
|
||||
path[#path+1] = ''
|
||||
end
|
||||
|
||||
filepath = table.concat(path, '/')
|
||||
|
||||
local entries = {}
|
||||
local _, e
|
||||
for _, e in luci.util.vspairs(nixio.util.consume((nixio.fs.dir(filepath)))) do
|
||||
local p = filepath .. e
|
||||
local s = nixio.fs.stat(p)
|
||||
if s then
|
||||
entries[#entries+1] = {
|
||||
name = e,
|
||||
path = p,
|
||||
type = s.type
|
||||
}
|
||||
end
|
||||
end
|
||||
-%>
|
||||
<div id="path">
|
||||
Location:
|
||||
<% for i, dir in ipairs(path) do %>
|
||||
<% if i == 1 then %>
|
||||
<a href="<%=url(unpack(baseurl))%>?field=<%=luci.http.urlencode(field)%>">(root)</a>
|
||||
<% elseif next(path, i) then %>
|
||||
<% baseurl[#baseurl+1] = luci.http.urlencode(dir) %>
|
||||
/ <a href="<%=url(unpack(baseurl))%>?field=<%=luci.http.urlencode(field)%>"><%=pcdata(dir)%></a>
|
||||
<% else %>
|
||||
<% baseurl[#baseurl+1] = luci.http.urlencode(dir) %>
|
||||
/ <%=pcdata(dir)%>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div id="listing">
|
||||
<ul>
|
||||
<% for _, e in ipairs(entries) do if e.type == 'dir' then -%>
|
||||
<li class="dir">
|
||||
<img src="<%=resource%>/cbi/folder.gif" alt="<%:Directory%>" />
|
||||
<a href="<%=url(unpack(baseurl))%>/<%=luci.http.urlencode(e.name)%>?field=<%=luci.http.urlencode(field)%>"><%=pcdata(e.name)%>/</a>
|
||||
</li>
|
||||
<% end end -%>
|
||||
|
||||
<% for _, e in ipairs(entries) do if e.type ~= 'dir' then -%>
|
||||
<li class="file">
|
||||
<img src="<%=resource%>/cbi/file.gif" alt="<%:File%>" />
|
||||
<a href="#" onclick="callback('<%=luci.http.urlencode(e.path)%>')"><%=pcdata(e.name)%></a>
|
||||
</li>
|
||||
<% end end -%>
|
||||
</ul>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
|
@ -1,73 +0,0 @@
|
|||
<%+cbi/valueheader%>
|
||||
|
||||
<%-
|
||||
local utl = require "luci.util"
|
||||
local fwm = require "luci.model.firewall".init()
|
||||
local nwm = require "luci.model.network".init()
|
||||
|
||||
local zone, fwd, fz
|
||||
local value = self:formvalue(section)
|
||||
if not value or value == "-" then
|
||||
value = self:cfgvalue(section) or self.default
|
||||
end
|
||||
|
||||
local def = fwm:get_defaults()
|
||||
local zone = fwm:get_zone(value)
|
||||
local empty = true
|
||||
|
||||
local function render_zone(zone)
|
||||
-%>
|
||||
<label class="zonebadge" style="background-color:<%=zone:get_color()%>">
|
||||
<strong><%=zone:name()%></strong>
|
||||
<div class="cbi-tooltip">
|
||||
<%-
|
||||
local zempty = true
|
||||
for _, net in ipairs(zone:get_networks()) do
|
||||
net = nwm:get_network(net)
|
||||
if net then
|
||||
zempty = false
|
||||
-%>
|
||||
<span class="ifacebadge<% if net:name() == self.network then %> ifacebadge-active<% end %>"><%=net:name()%>: 
|
||||
<%
|
||||
local nempty = true
|
||||
for _, iface in ipairs(net:is_bridge() and net:get_interfaces() or { net:get_interface() }) do
|
||||
nempty = false
|
||||
%>
|
||||
<img<%=attr("title", iface:get_i18n())%> src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" />
|
||||
<% end %>
|
||||
<% if nempty then %><em><%:(empty)%></em><% end %>
|
||||
</span>
|
||||
<%- end end -%>
|
||||
<% if zempty then %><span class="ifacebadge"><em><%:(empty)%></em></span><% end %>
|
||||
</div>
|
||||
</label>
|
||||
<%-
|
||||
end
|
||||
-%>
|
||||
|
||||
<% if zone then %>
|
||||
<div class="zone-forwards">
|
||||
<div class="zone-src">
|
||||
<%=render_zone(zone)%>
|
||||
</div>
|
||||
<span>⇒</span>
|
||||
<div class="zone-dest">
|
||||
<%
|
||||
for _, fwd in ipairs(zone:get_forwardings_by("src")) do
|
||||
fz = fwd:dest_zone()
|
||||
if fz then
|
||||
empty = false
|
||||
render_zone(fz)
|
||||
end
|
||||
end
|
||||
if empty then
|
||||
%>
|
||||
<label class="zonebadge zonebadge-empty">
|
||||
<strong><%=zone:forward():upper()%></strong>
|
||||
</label>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<%+cbi/valuefooter%>
|
|
@ -1,108 +0,0 @@
|
|||
<%+cbi/valueheader%>
|
||||
|
||||
<%-
|
||||
local utl = require "luci.util"
|
||||
local fwm = require "luci.model.firewall".init()
|
||||
local nwm = require "luci.model.network".init()
|
||||
|
||||
local zone, net, iface
|
||||
local zones = fwm:get_zones()
|
||||
local value = self:formvalue(section)
|
||||
if not value or value == "-" then
|
||||
value = self:cfgvalue(section) or self.default
|
||||
end
|
||||
|
||||
local selected = false
|
||||
local checked = { }
|
||||
|
||||
for value in utl.imatch(value) do
|
||||
checked[value] = true
|
||||
end
|
||||
|
||||
if not next(checked) then
|
||||
checked[""] = true
|
||||
end
|
||||
-%>
|
||||
|
||||
<div class="cbi-dropdown" dropdown-items="5" placeholder="<%:-- please select -- %>"<%=
|
||||
attr("name", cbid) ..
|
||||
ifattr(self.widget == "checkbox", "multiple", "multiple") ..
|
||||
ifattr(self.rmempty or self.optional, "optional", "optional")
|
||||
%>>
|
||||
<script type="item-template"><!--
|
||||
<li value="{{value}}">
|
||||
<span class="zonebadge" style="background:repeating-linear-gradient(45deg,rgba(204,204,204,0.5),rgba(204,204,204,0.5) 5px,rgba(255,255,255,0.5) 5px,rgba(255,255,255,0.5) 10px)">
|
||||
<strong>{{value}}:</strong><em>(<%:create%>)</em>
|
||||
</span>
|
||||
</li>
|
||||
--></script>
|
||||
<ul>
|
||||
<% if self.allowlocal then %>
|
||||
<li value=""<%=ifattr(checked[""], "selected", "selected")%>>
|
||||
<span style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge">
|
||||
<strong><%:Device%></strong>
|
||||
<% if self.allowany and self.allowlocal then -%>
|
||||
(<%= self.alias ~= "dest"
|
||||
and translate("output") or translate("input") %>)
|
||||
<%- end %>
|
||||
</span>
|
||||
</li>
|
||||
<% elseif self.widget ~= "checkbox" and (self.rmempty or self.optional) then %>
|
||||
<li value=""<%=ifattr(checked[""], "selected", "selected")%>>
|
||||
<span class="zonebadge">
|
||||
<em><%:unspecified%></em>
|
||||
</span>
|
||||
</li>
|
||||
<% end %>
|
||||
<% if self.allowany then %>
|
||||
<li value="*"<%=ifattr(checked["*"], "selected", "selected")%>>
|
||||
<span style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge">
|
||||
<strong><%:Any zone%></strong>
|
||||
<% if self.allowany and self.allowlocal then %>(<%:forward%>)<% end %>
|
||||
</span>
|
||||
</li>
|
||||
<% end %>
|
||||
<%
|
||||
for _, zone in utl.spairs(zones, function(a,b) return (zones[a]:name() < zones[b]:name()) end) do
|
||||
if zone:name() ~= self.exclude then
|
||||
selected = selected or (value == zone:name())
|
||||
%>
|
||||
<li<%=attr("value", zone:name()) .. ifattr(checked[zone:name()], "selected", "selected")%>>
|
||||
<span style="background-color:<%=zone:get_color()%>" class="zonebadge">
|
||||
<strong><%=zone:name()%>:</strong>
|
||||
<%-
|
||||
local zempty = true
|
||||
for _, net in ipairs(zone:get_networks()) do
|
||||
net = nwm:get_network(net)
|
||||
if net then
|
||||
zempty = false
|
||||
-%>
|
||||
<span class="ifacebadge<% if net:name() == self.network then %> ifacebadge-active<% end %>"><%=net:name()%>:
|
||||
<%-
|
||||
local nempty = true
|
||||
for _, iface in ipairs(net:is_bridge() and net:get_interfaces() or { net:get_interface() }) do
|
||||
nempty = false
|
||||
%>
|
||||
<img<%=attr("title", iface:get_i18n())%> src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" />
|
||||
<% end %>
|
||||
<% if nempty then %><em><%:(empty)%></em><% end -%>
|
||||
</span>
|
||||
<%- end end -%>
|
||||
<%- if zempty then %><em><%:(empty)%></em><% end -%>
|
||||
</span>
|
||||
</li>
|
||||
<% end end %>
|
||||
|
||||
<% if self.widget ~= "checkbox" and not self.nocreate then %>
|
||||
<li value="-">
|
||||
<span class="zonebadge">
|
||||
<em><%:create%>:</em>
|
||||
<input type="password" style="display:none" />
|
||||
<input class="create-item-input" type="text" />
|
||||
</span>
|
||||
</li>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<%+cbi/valuefooter%>
|
|
@ -1,41 +0,0 @@
|
|||
<%
|
||||
local display_back = (redirect and not flow.hidebackbtn)
|
||||
local display_skip = (flow.skip)
|
||||
local display_apply = (not autoapply and not flow.hideapplybtn)
|
||||
local display_save = (not flow.hidesavebtn)
|
||||
local display_reset = (not flow.hideresetbtn)
|
||||
|
||||
if pageaction and
|
||||
(display_back or display_skip or display_apply or display_save or display_reset)
|
||||
then
|
||||
%><div class="cbi-page-actions"><%
|
||||
|
||||
if display_back then
|
||||
%><input class="cbi-button cbi-button-link" type="button" value="<%:Back to Overview%>" onclick="location.href='<%=pcdata(redirect)%>'" /> <%
|
||||
end
|
||||
|
||||
if display_skip then
|
||||
%><input class="cbi-button cbi-button-skip" type="button" value="<%:Skip%>" onclick="cbi_submit(this, 'cbi.skip')" /> <%
|
||||
end
|
||||
|
||||
if display_apply then
|
||||
%><input class="cbi-button cbi-button-apply" type="button" value="<%:Save & Apply%>" onclick="cbi_submit(this, 'cbi.apply')" /> <%
|
||||
end
|
||||
|
||||
if display_save then
|
||||
%><input class="cbi-button cbi-button-save" type="submit" value="<%:Save%>" /> <%
|
||||
end
|
||||
|
||||
if display_reset then
|
||||
%><input class="cbi-button cbi-button-reset" type="button" value="<%:Reset%>" onclick="location.href='<%=REQUEST_URI%>'" /> <%
|
||||
end
|
||||
|
||||
%></div><%
|
||||
end
|
||||
%>
|
||||
|
||||
</form>
|
||||
|
||||
<script type="text/javascript">cbi_init();</script>
|
||||
|
||||
<%+footer%>
|