Merge r4097
[project/luci.git] / libs / uci / luasrc / model / uci.lua
1 --[[
2 LuCI - UCI model
3
4 Description:
5 Generalized UCI model
6
7 FileId:
8 $Id$
9
10 License:
11 Copyright 2008 Steven Barth <steven@midlink.org>
12
13 Licensed under the Apache License, Version 2.0 (the "License");
14 you may not use this file except in compliance with the License.
15 You may obtain a copy of the License at
16
17         http://www.apache.org/licenses/LICENSE-2.0
18
19 Unless required by applicable law or agreed to in writing, software
20 distributed under the License is distributed on an "AS IS" BASIS,
21 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22 See the License for the specific language governing permissions and
23 limitations under the License.
24
25 ]]--
26 local os    = require "os"
27 local uci   = require "uci"
28 local util  = require "luci.util"
29 local table = require "table"
30
31
32 local setmetatable, rawget, rawset = setmetatable, rawget, rawset
33 local error, pairs, ipairs, tostring = error, pairs, ipairs, tostring
34 local require, getmetatable, type = require, getmetatable, type
35
36 --- LuCI UCI model library.
37 -- @cstyle      instance
38 module "luci.model.uci"
39
40 --- Create a new UCI-Cursor.
41 -- @class function
42 -- @name cursor
43 -- @return      UCI-Cursor
44 cursor = uci.cursor
45
46 APIVERSION = uci.APIVERSION
47
48 --- Create a new Cursor initialized to the state directory.
49 -- @return UCI cursor
50 function cursor_state()
51         return cursor(nil, "/var/state")
52 end
53
54
55 local Cursor = getmetatable(cursor())
56
57 --- Applies UCI configuration changes
58 -- @param configlist            List of UCI configurations
59 -- @param command                       Don't apply only return the command
60 function Cursor.apply(self, configlist, command)
61         configlist = self:_affected(configlist)
62         local reloadcmd = "/sbin/luci-reload " .. table.concat(configlist, " ")
63
64         return command and reloadcmd or os.execute(reloadcmd .. " >/dev/null 2>&1")
65 end
66
67
68 --- Delete all sections of a given type that match certain criteria.
69 -- @param config                UCI config
70 -- @param type                  UCI section type
71 -- @param comparator    Function that will be called for each section and
72 -- returns a boolean whether to delete the current section (optional)
73 function Cursor.delete_all(self, config, stype, comparator)
74         local del = {}
75
76         if type(comparator) == "table" then
77                 local tbl = comparator
78                 comparator = function(section)
79                         for k, v in pairs(tbl) do
80                                 if section[k] ~= v then
81                                         return false
82                                 end
83                         end
84                         return true
85                 end
86         end
87
88         local function helper (section)
89
90                 if not comparator or comparator(section) then
91                         del[#del+1] = section[".name"]
92                 end
93         end
94
95         self:foreach(config, stype, helper)
96
97         for i, j in ipairs(del) do
98                 self:delete(config, j)
99         end
100 end
101
102 --- Create a new section and initialize it with data.
103 -- @param config        UCI config
104 -- @param type          UCI section type
105 -- @param name          UCI section name (optional)
106 -- @param values        Table of key - value pairs to initialize the section with
107 -- @return                      Name of created section
108 function Cursor.section(self, config, type, name, values)
109         local stat = true
110         if name then
111                 stat = self:set(config, name, type)
112         else
113                 name = self:add(config, type)
114                 stat = name and true
115         end
116
117         if stat and values then
118                 stat = self:tset(config, name, values)
119         end
120
121         return stat and name
122 end
123
124 --- Updated the data of a section using data from a table.
125 -- @param config        UCI config
126 -- @param section       UCI section name (optional)
127 -- @param values        Table of key - value pairs to update the section with
128 function Cursor.tset(self, config, section, values)
129         local stat = true
130         for k, v in pairs(values) do
131                 if k:sub(1, 1) ~= "." then
132                         stat = stat and self:set(config, section, k, v)
133                 end
134         end
135         return stat
136 end
137
138 --- Get a boolean option and return it's value as true or false.
139 -- @param config        UCI config
140 -- @param section       UCI section name
141 -- @param option        UCI option
142 -- @return                      Boolean
143 function Cursor.get_bool(self, ...)
144         local val = self:get(...)
145         return ( val == "1" or val == "true" or val == "yes" or val == "on" )
146 end
147
148 --- Get an option or list and return values as table.
149 -- @param config        UCI config
150 -- @param section       UCI section name
151 -- @param option        UCI option
152 -- @return                      UCI value
153 function Cursor.get_list(self, config, section, option)
154         if config and section and option then
155                 local val = self:get(config, section, option)
156                 return ( type(val) == "table" and val or { val } )
157         end
158         return nil
159 end
160
161 --- Set given values as list.
162 -- @param config        UCI config
163 -- @param section       UCI section name
164 -- @param option        UCI option
165 -- @param value         UCI value
166 -- @return                      Boolean whether operation succeeded
167 function Cursor.set_list(self, config, section, option, value)
168         if config and section and option then
169                 return self:set(
170                         config, section, option,
171                         ( type(value) == "table" and value or { value } )
172                 )
173         end
174         return false
175 end
176
177 -- Return a list of initscripts affected by configuration changes.
178 function Cursor._affected(self, configlist)
179         configlist = type(configlist) == "table" and configlist or {configlist}
180
181         local c = cursor()
182         c:load("ucitrack")
183
184         -- Resolve dependencies
185         local reloadlist = {}
186
187         local function _resolve_deps(name)
188                 local reload = {name}
189                 local deps = {}
190
191                 c:foreach("ucitrack", name,
192                         function(section)
193                                 if section.affects then
194                                         for i, aff in ipairs(section.affects) do
195                                                 deps[#deps+1] = aff
196                                         end
197                                 end
198                         end)
199
200                 for i, dep in ipairs(deps) do
201                         for j, add in ipairs(_resolve_deps(dep)) do
202                                 reload[#reload+1] = add
203                         end
204                 end
205
206                 return reload
207         end
208
209         -- Collect initscripts
210         for j, config in ipairs(configlist) do
211                 for i, e in ipairs(_resolve_deps(config)) do
212                         if not util.contains(reloadlist, e) then
213                                 reloadlist[#reloadlist+1] = e
214                         end
215                 end
216         end
217
218         return reloadlist
219 end
220
221
222 --- Add an anonymous section.
223 -- @class function
224 -- @name Cursor.add
225 -- @param config        UCI config
226 -- @param type          UCI section type
227 -- @return                      Name of created section
228
229 --- Get a table of unsaved changes.
230 -- @class function
231 -- @name Cursor.changes
232 -- @param config        UCI config
233 -- @return                      Table of changes
234
235 --- Commit unsaved changes.
236 -- @class function
237 -- @name Cursor.commit
238 -- @param config        UCI config
239 -- @return                      Boolean whether operation succeeded
240 -- @see Cursor.revert
241
242 --- Deletes a section or an option.
243 -- @class function
244 -- @name Cursor.delete
245 -- @param config        UCI config
246 -- @param section       UCI section name
247 -- @param option        UCI option (optional)
248 -- @return                      Boolean whether operation succeeded
249
250 --- Call a function for every section of a certain type.
251 -- @class function
252 -- @name Cursor.foreach
253 -- @param config        UCI config
254 -- @param type          UCI section type
255 -- @param callback      Function to be called
256 -- @return                      Boolean whether operation succeeded
257
258 --- Get a section type or an option
259 -- @class function
260 -- @name Cursor.get
261 -- @param config        UCI config
262 -- @param section       UCI section name
263 -- @param option        UCI option (optional)
264 -- @return                      UCI value
265
266 --- Get all sections of a config or all values of a section.
267 -- @class function
268 -- @name Cursor.get_all
269 -- @param config        UCI config
270 -- @param section       UCI section name (optional)
271 -- @return                      Table of UCI sections or table of UCI values
272
273 --- Manually load a config.
274 -- @class function
275 -- @name Cursor.load
276 -- @param config        UCI config
277 -- @return                      Boolean whether operation succeeded
278 -- @see Cursor.save
279 -- @see Cursor.unload
280
281 --- Revert unsaved changes.
282 -- @class function
283 -- @name Cursor.revert
284 -- @param config        UCI config
285 -- @return                      Boolean whether operation succeeded
286 -- @see Cursor.commit
287
288 --- Saves changes made to a config to make them committable.
289 -- @class function
290 -- @name Cursor.save
291 -- @param config        UCI config
292 -- @return                      Boolean whether operation succeeded
293 -- @see Cursor.load
294 -- @see Cursor.unload
295
296 --- Set a value or create a named section.
297 -- @class function
298 -- @name Cursor.set
299 -- @param config        UCI config
300 -- @param section       UCI section name
301 -- @param option        UCI option or UCI section type
302 -- @param value         UCI value or nil if you want to create a section
303 -- @return                      Boolean whether operation succeeded
304
305 --- Get the configuration directory.
306 -- @class function
307 -- @name Cursor.get_confdir
308 -- @return                      Configuration directory
309
310 --- Get the directory for uncomitted changes.
311 -- @class function
312 -- @name Cursor.get_savedir
313 -- @return                      Save directory
314
315 --- Set the configuration directory.
316 -- @class function
317 -- @name Cursor.set_confdir
318 -- @param directory     UCI configuration directory
319 -- @return                      Boolean whether operation succeeded
320
321 --- Set the directory for uncommited changes.
322 -- @class function
323 -- @name Cursor.set_savedir
324 -- @param directory     UCI changes directory
325 -- @return                      Boolean whether operation succeeded
326
327 --- Discard changes made to a config.
328 -- @class function
329 -- @name Cursor.unload
330 -- @param config        UCI config
331 -- @return                      Boolean whether operation succeeded
332 -- @see Cursor.load
333 -- @see Cursor.save