1
0
Fork 0
mirror of https://github.com/Ysurac/openmptcprouter-feeds.git synced 2025-03-09 15:40:03 +00:00

Add macvlan support

This commit is contained in:
Ycarus 2018-01-23 15:36:03 +01:00
parent 40fdd921b9
commit 9f8643647e
255 changed files with 134998 additions and 0 deletions

View file

@ -0,0 +1,67 @@
-- 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)"

View file

@ -0,0 +1,4 @@
-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org>
-- Licensed to the public under the Apache License 2.0.
local map, section, net = ...

View file

@ -0,0 +1,97 @@
-- 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

View file

@ -0,0 +1,566 @@
-- 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)
return zone(self:src())
end
function forwarding.dest_zone(self)
return zone(self:dest())
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

View file

@ -0,0 +1,242 @@
-- 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 pkg = ""
for k, v in pairs({...}) do
pkg = pkg .. " '" .. v:gsub("'", "") .. "'"
end
local c = "%s %s %s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" %{ ipkg, cmd, pkg }
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(act, pkg)
local cmd = ipkg .. " " .. act
if pkg then
cmd = cmd .. " '" .. pkg:gsub("'", "") .. "'"
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(cmd .. (" >%s 2>/dev/null" % 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 fd = io.popen(ipkg .. " " .. action ..
(pat and (" '%s'" % pat:gsub("'", "")) or ""))
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

View file

@ -0,0 +1,125 @@
---[[
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
]]

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,236 @@
-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.
local os = require "os"
local uci = require "uci"
local util = require "luci.util"
local table = require "table"
local setmetatable, rawget, rawset = setmetatable, rawget, rawset
local require, getmetatable = require, getmetatable
local error, pairs, ipairs = error, pairs, ipairs
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"
cursor = uci.cursor
APIVERSION = uci.APIVERSION
function cursor_state()
return cursor(nil, "/var/state")
end
inst = cursor()
inst_state = cursor_state()
local Cursor = getmetatable(inst)
function Cursor.apply(self, configlist, command)
configlist = self:_affected(configlist)
if command then
return { "/sbin/luci-reload", unpack(configlist) }
else
return os.execute("/sbin/luci-reload %s >/dev/null 2>&1"
% table.concat(configlist, " "))
end
end
-- returns a boolean whether to delete the current section (optional)
function Cursor.delete_all(self, config, stype, comparator)
local del = {}
if type(comparator) == "table" then
local tbl = comparator
comparator = function(section)
for k, v in pairs(tbl) do
if section[k] ~= v then
return false
end
end
return true
end
end
local function helper (section)
if not comparator or comparator(section) then
del[#del+1] = section[".name"]
end
end
self:foreach(config, stype, helper)
for i, j in ipairs(del) do
self:delete(config, j)
end
end
function Cursor.section(self, config, type, name, values)
local stat = true
if name then
stat = self:set(config, name, type)
else
name = self:add(config, type)
stat = name and true
end
if stat and values then
stat = self:tset(config, name, values)
end
return stat and name
end
function Cursor.tset(self, config, section, values)
local stat = true
for k, v in pairs(values) do
if k:sub(1, 1) ~= "." then
stat = stat and self:set(config, section, k, v)
end
end
return stat
end
function Cursor.get_bool(self, ...)
local val = self:get(...)
return ( val == "1" or val == "true" or val == "yes" or val == "on" )
end
function Cursor.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 Cursor.get_first(self, conf, stype, opt, def)
local rv = def
self:foreach(conf, stype,
function(s)
local val = not opt and s['.name'] or s[opt]
if type(def) == "number" then
val = tonumber(val)
elseif type(def) == "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 Cursor.set_list(self, config, section, option, value)
if config and section and option then
if not value or #value == 0 then
return self:delete(config, section, option)
end
return self:set(
config, section, option,
( type(value) == "table" and value or { value } )
)
end
return false
end
-- Return a list of initscripts affected by configuration changes.
function Cursor._affected(self, configlist)
configlist = type(configlist) == "table" and configlist or {configlist}
local c = cursor()
c:load("ucitrack")
-- Resolve dependencies
local reloadlist = {}
local function _resolve_deps(name)
local reload = {name}
local deps = {}
c:foreach("ucitrack", name,
function(section)
if section.affects then
for i, aff in ipairs(section.affects) do
deps[#deps+1] = aff
end
end
end)
for i, dep in ipairs(deps) do
for j, add in ipairs(_resolve_deps(dep)) do
reload[#reload+1] = add
end
end
return reload
end
-- Collect initscripts
for j, config in ipairs(configlist) do
for i, e in ipairs(_resolve_deps(config)) do
if not util.contains(reloadlist, e) then
reloadlist[#reloadlist+1] = e
end
end
end
return reloadlist
end
-- curser, means it the parent unloads or loads configs, the sub state will
-- do so as well.
function Cursor.substate(self)
Cursor._substates = Cursor._substates or { }
Cursor._substates[self] = Cursor._substates[self] or cursor_state()
return Cursor._substates[self]
end
local _load = Cursor.load
function Cursor.load(self, ...)
if Cursor._substates and Cursor._substates[self] then
_load(Cursor._substates[self], ...)
end
return _load(self, ...)
end
local _unload = Cursor.unload
function Cursor.unload(self, ...)
if Cursor._substates and Cursor._substates[self] then
_unload(Cursor._substates[self], ...)
end
return _unload(self, ...)
end

View file

@ -0,0 +1,299 @@
---[[
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
@class function
@name Cursor.apply
@param configlist List of UCI configurations
@param command Don't apply only return the command
]]
---[[
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. Raw values will become a single item table.
@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
]]
---[[
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
]]
---[[
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
]]