luci/modules/luci-base/luasrc/model/uci.lua

383 lines
9.9 KiB
Lua
Raw Normal View History

-- Copyright 2008 Steven Barth <steven@midlink.org>
-- Licensed to the public under the Apache License 2.0.
2008-08-27 13:49:32 +00:00
local os = require "os"
2008-08-27 21:32:05 +00:00
local uci = require "uci"
local util = require "luci.util"
local table = require "table"
2008-08-27 13:49:32 +00:00
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
--- LuCI UCI model library.
2009-08-13 11:46:03 +00:00
-- 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.
2008-08-29 15:47:56 +00:00
-- @cstyle instance
2008-09-01 21:40:08 +00:00
module "luci.model.uci"
2008-08-28 10:18:10 +00:00
--- Create a new UCI-Cursor.
-- @class function
-- @name cursor
-- @return UCI-Cursor
2008-08-26 23:00:44 +00:00
cursor = uci.cursor
2008-08-28 10:18:10 +00:00
2008-08-26 23:00:44 +00:00
APIVERSION = uci.APIVERSION
2008-08-28 10:18:10 +00:00
--- Create a new Cursor initialized to the state directory.
2008-08-26 23:00:44 +00:00
-- @return UCI cursor
function cursor_state()
return cursor(nil, "/var/state")
end
2008-08-29 15:47:56 +00:00
2009-11-10 16:02:48 +00:00
inst = cursor()
inst_state = cursor_state()
local Cursor = getmetatable(inst)
2008-09-06 13:51:51 +00:00
--- Applies UCI configuration changes
-- @param configlist List of UCI configurations
-- @param command Don't apply only return the command
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
2008-09-06 13:51:51 +00:00
2008-07-24 16:21:32 +00:00
--- Delete all sections of a given type that match certain criteria.
-- @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)
2008-09-05 12:05:06 +00:00
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)
2008-08-26 23:00:44 +00:00
if not comparator or comparator(section) then
del[#del+1] = section[".name"]
2008-08-26 23:00:44 +00:00
end
end
2008-09-05 12:05:06 +00:00
self:foreach(config, stype, helper)
for i, j in ipairs(del) do
2008-08-26 23:00:44 +00:00
self:delete(config, j)
end
end
2008-07-24 16:21:32 +00:00
--- Create a new section and initialize it with data.
-- @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
2008-08-26 23:00:44 +00:00
function Cursor.section(self, config, type, name, values)
local stat = true
if name then
2008-08-26 23:00:44 +00:00
stat = self:set(config, name, type)
else
2008-08-26 23:00:44 +00:00
name = self:add(config, type)
stat = name and true
end
if stat and values then
2008-08-26 23:00:44 +00:00
stat = self:tset(config, name, values)
end
return stat and name
end
2008-07-24 16:21:32 +00:00
--- Updated the data of a section using data from a table.
-- @param config UCI config
-- @param section UCI section name (optional)
-- @param values Table of key - value pairs to update the section with
2008-08-26 23:00:44 +00:00
function Cursor.tset(self, config, section, values)
local stat = true
for k, v in pairs(values) do
if k:sub(1, 1) ~= "." then
2008-08-26 23:00:44 +00:00
stat = stat and self:set(config, section, k, v)
end
end
return stat
end
2008-07-24 16:21:32 +00:00
--- Get a boolean option and return it's value as true or false.
-- @param config UCI config
-- @param section UCI section name
-- @param option UCI option
-- @return Boolean
function Cursor.get_bool(self, ...)
local val = self:get(...)
return ( val == "1" or val == "true" or val == "yes" or val == "on" )
end
--- Get an option or list and return values as table.
-- @param config UCI config
-- @param section UCI section name
-- @param option UCI option
-- @return UCI value
2008-08-26 23:00:44 +00:00
function Cursor.get_list(self, config, section, option)
if config and section and option then
2008-08-26 23:00:44 +00:00
local val = self:get(config, section, option)
return ( type(val) == "table" and val or { val } )
end
return nil
end
--- Get the given option from the first section with the given type.
-- @param config UCI config
-- @param type UCI section type
-- @param option UCI option (optional)
-- @param default Default value (optional)
-- @return UCI value
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
--- Set given values as list.
-- @param config UCI config
-- @param section UCI section name
-- @param option UCI option
-- @param value UCI value
-- @return Boolean whether operation succeeded
2008-08-26 23:00:44 +00:00
function Cursor.set_list(self, config, section, option, value)
if config and section and option then
2008-08-26 23:00:44 +00:00
return self:set(
config, section, option,
( type(value) == "table" and value or { value } )
)
end
return false
end
2008-09-06 13:51:51 +00:00
-- 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 = {}
2008-09-06 13:51:51 +00:00
c:foreach("ucitrack", name,
function(section)
if section.affects then
for i, aff in ipairs(section.affects) do
deps[#deps+1] = aff
2008-09-06 13:51:51 +00:00
end
end
end)
2008-09-06 13:51:51 +00:00
for i, dep in ipairs(deps) do
for j, add in ipairs(_resolve_deps(dep)) do
reload[#reload+1] = add
2008-09-06 13:51:51 +00:00
end
end
2008-09-06 13:51:51 +00:00
return reload
end
2008-09-06 13:51:51 +00:00
-- 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
2008-09-06 13:51:51 +00:00
end
end
end
2008-09-06 13:51:51 +00:00
return reloadlist
end
--- 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.
-- @return UCI state cursor tied to the parent cursor
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
2008-09-06 13:51:51 +00:00
2008-07-24 16:21:32 +00:00
--- Add an anonymous section.
-- @class function
2008-08-26 23:00:44 +00:00
-- @name Cursor.add
2008-07-24 16:21:32 +00:00
-- @param config UCI config
-- @param type UCI section type
-- @return Name of created section
2009-08-13 11:46:03 +00:00
--- Get a table of saved but uncommitted changes.
2008-07-24 16:21:32 +00:00
-- @class function
2008-08-26 23:00:44 +00:00
-- @name Cursor.changes
2008-07-24 16:21:32 +00:00
-- @param config UCI config
-- @return Table of changes
2009-08-13 11:46:03 +00:00
-- @see Cursor.save
2008-07-24 16:21:32 +00:00
2009-08-13 11:46:03 +00:00
--- Commit saved changes.
2008-07-24 16:21:32 +00:00
-- @class function
2008-08-26 23:00:44 +00:00
-- @name Cursor.commit
2008-07-24 16:21:32 +00:00
-- @param config UCI config
-- @return Boolean whether operation succeeded
2008-08-28 10:18:10 +00:00
-- @see Cursor.revert
2009-08-13 11:46:03 +00:00
-- @see Cursor.save
2008-07-24 16:21:32 +00:00
--- Deletes a section or an option.
-- @class function
2008-08-26 23:00:44 +00:00
-- @name Cursor.delete
2008-07-24 16:21:32 +00:00
-- @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
2008-08-26 23:00:44 +00:00
-- @name Cursor.foreach
2008-07-24 16:21:32 +00:00
-- @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
2008-08-26 23:00:44 +00:00
-- @name Cursor.get
2008-07-24 16:21:32 +00:00
-- @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
2008-08-26 23:00:44 +00:00
-- @name Cursor.get_all
2008-07-24 16:21:32 +00:00
-- @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
2008-08-26 23:00:44 +00:00
-- @name Cursor.load
2008-07-24 16:21:32 +00:00
-- @param config UCI config
-- @return Boolean whether operation succeeded
2008-08-28 10:18:10 +00:00
-- @see Cursor.save
-- @see Cursor.unload
2008-07-24 16:21:32 +00:00
2009-08-13 11:46:03 +00:00
--- Revert saved but uncommitted changes.
2008-07-24 16:21:32 +00:00
-- @class function
2008-08-26 23:00:44 +00:00
-- @name Cursor.revert
2008-07-24 16:21:32 +00:00
-- @param config UCI config
-- @return Boolean whether operation succeeded
2008-08-28 10:18:10 +00:00
-- @see Cursor.commit
2009-08-13 11:46:03 +00:00
-- @see Cursor.save
2008-07-24 16:21:32 +00:00
--- Saves changes made to a config to make them committable.
-- @class function
2008-08-26 23:00:44 +00:00
-- @name Cursor.save
2008-07-24 16:21:32 +00:00
-- @param config UCI config
-- @return Boolean whether operation succeeded
2008-08-28 10:18:10 +00:00
-- @see Cursor.load
-- @see Cursor.unload
2008-07-24 16:21:32 +00:00
--- Set a value or create a named section.
-- @class function
2008-08-26 23:00:44 +00:00
-- @name Cursor.set
2008-07-24 16:21:32 +00:00
-- @param config UCI config
-- @param section UCI section name
-- @param option UCI option or UCI section type
-- @param value UCI value or nil if you want to create a section
-- @return Boolean whether operation succeeded
2008-08-26 23:00:44 +00:00
--- 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
2008-07-24 16:21:32 +00:00
--- Set the configuration directory.
-- @class function
2008-08-26 23:00:44 +00:00
-- @name Cursor.set_confdir
2008-07-24 16:21:32 +00:00
-- @param directory UCI configuration directory
-- @return Boolean whether operation succeeded
--- Set the directory for uncommited changes.
-- @class function
2008-08-26 23:00:44 +00:00
-- @name Cursor.set_savedir
2008-07-24 16:21:32 +00:00
-- @param directory UCI changes directory
-- @return Boolean whether operation succeeded
--- Discard changes made to a config.
-- @class function
2008-08-26 23:00:44 +00:00
-- @name Cursor.unload
2008-07-24 16:21:32 +00:00
-- @param config UCI config
-- @return Boolean whether operation succeeded
2008-08-28 10:18:10 +00:00
-- @see Cursor.load
-- @see Cursor.save