a394563047c37e2567325d4fee0d75c08e491ab2
[project/luci.git] / libs / core / 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 require, getmetatable = require, getmetatable
34 local error, pairs, ipairs = error, pairs, ipairs
35 local type, tostring, tonumber, unpack = type, tostring, tonumber, unpack
36
37 --- LuCI UCI model library.
38 -- The typical workflow for UCI is: Get a cursor instance from the
39 -- cursor factory, modify data (via Cursor.add, Cursor.delete, etc.),
40 -- save the changes to the staging area via Cursor.save and finally
41 -- Cursor.commit the data to the actual config files.
42 -- LuCI then needs to Cursor.apply the changes so deamons etc. are
43 -- reloaded.
44 -- @cstyle instance
45 module "luci.model.uci"
46
47 --- Create a new UCI-Cursor.
48 -- @class function
49 -- @name cursor
50 -- @return UCI-Cursor
51 cursor = uci.cursor
52
53 APIVERSION = uci.APIVERSION
54
55 --- Create a new Cursor initialized to the state directory.
56 -- @return UCI cursor
57 function cursor_state()
58 return cursor(nil, "/var/state")
59 end
60
61
62 inst = cursor()
63 inst_state = cursor_state()
64
65 local Cursor = getmetatable(inst)
66
67 --- Applies UCI configuration changes
68 -- @param configlist List of UCI configurations
69 -- @param command Don't apply only return the command
70 function Cursor.apply(self, configlist, command)
71 configlist = self:_affected(configlist)
72 if command then
73 return { "/sbin/luci-reload", unpack(configlist) }
74 else
75 return os.execute("/sbin/luci-reload %s >/dev/null 2>&1"
76 % table.concat(configlist, " "))
77 end
78 end
79
80
81 --- Delete all sections of a given type that match certain criteria.
82 -- @param config UCI config
83 -- @param type UCI section type
84 -- @param comparator Function that will be called for each section and
85 -- returns a boolean whether to delete the current section (optional)
86 function Cursor.delete_all(self, config, stype, comparator)
87 local del = {}
88
89 if type(comparator) == "table" then
90 local tbl = comparator
91 comparator = function(section)
92 for k, v in pairs(tbl) do
93 if section[k] ~= v then
94 return false
95 end
96 end
97 return true
98 end
99 end
100
101 local function helper (section)
102
103 if not comparator or comparator(section) then
104 del[#del+1] = section[".name"]
105 end
106 end
107
108 self:foreach(config, stype, helper)
109
110 for i, j in ipairs(del) do
111 self:delete(config, j)
112 end
113 end
114
115 --- Create a new section and initialize it with data.
116 -- @param config UCI config
117 -- @param type UCI section type
118 -- @param name UCI section name (optional)
119 -- @param values Table of key - value pairs to initialize the section with
120 -- @return Name of created section
121 function Cursor.section(self, config, type, name, values)
122 local stat = true
123 if name then
124 stat = self:set(config, name, type)
125 else
126 name = self:add(config, type)
127 stat = name and true
128 end
129
130 if stat and values then
131 stat = self:tset(config, name, values)
132 end
133
134 return stat and name
135 end
136
137 --- Updated the data of a section using data from a table.
138 -- @param config UCI config
139 -- @param section UCI section name (optional)
140 -- @param values Table of key - value pairs to update the section with
141 function Cursor.tset(self, config, section, values)
142 local stat = true
143 for k, v in pairs(values) do
144 if k:sub(1, 1) ~= "." then
145 stat = stat and self:set(config, section, k, v)
146 end
147 end
148 return stat
149 end
150
151 --- Get a boolean option and return it's value as true or false.
152 -- @param config UCI config
153 -- @param section UCI section name
154 -- @param option UCI option
155 -- @return Boolean
156 function Cursor.get_bool(self, ...)
157 local val = self:get(...)
158 return ( val == "1" or val == "true" or val == "yes" or val == "on" )
159 end
160
161 --- Get an option or list and return values as table.
162 -- @param config UCI config
163 -- @param section UCI section name
164 -- @param option UCI option
165 -- @return UCI value
166 function Cursor.get_list(self, config, section, option)
167 if config and section and option then
168 local val = self:get(config, section, option)
169 return ( type(val) == "table" and val or { val } )
170 end
171 return nil
172 end
173
174 --- Get the given option from the first section with the given type.
175 -- @param config UCI config
176 -- @param type UCI section type
177 -- @param option UCI option (optional)
178 -- @param default Default value (optional)
179 -- @return UCI value
180 function Cursor.get_first(self, conf, stype, opt, def)
181 local rv = def
182
183 self:foreach(conf, stype,
184 function(s)
185 local val = not opt and s['.name'] or s[opt]
186
187 if type(def) == "number" then
188 val = tonumber(val)
189 elseif type(def) == "boolean" then
190 val = (val == "1" or val == "true" or
191 val == "yes" or val == "on")
192 end
193
194 if val ~= nil then
195 rv = val
196 return false
197 end
198 end)
199
200 return rv
201 end
202
203 --- Set given values as list.
204 -- @param config UCI config
205 -- @param section UCI section name
206 -- @param option UCI option
207 -- @param value UCI value
208 -- @return Boolean whether operation succeeded
209 function Cursor.set_list(self, config, section, option, value)
210 if config and section and option then
211 return self:set(
212 config, section, option,
213 ( type(value) == "table" and value or { value } )
214 )
215 end
216 return false
217 end
218
219 -- Return a list of initscripts affected by configuration changes.
220 function Cursor._affected(self, configlist)
221 configlist = type(configlist) == "table" and configlist or {configlist}
222
223 local c = cursor()
224 c:load("ucitrack")
225
226 -- Resolve dependencies
227 local reloadlist = {}
228
229 local function _resolve_deps(name)
230 local reload = {name}
231 local deps = {}
232
233 c:foreach("ucitrack", name,
234 function(section)
235 if section.affects then
236 for i, aff in ipairs(section.affects) do
237 deps[#deps+1] = aff
238 end
239 end
240 end)
241
242 for i, dep in ipairs(deps) do
243 for j, add in ipairs(_resolve_deps(dep)) do
244 reload[#reload+1] = add
245 end
246 end
247
248 return reload
249 end
250
251 -- Collect initscripts
252 for j, config in ipairs(configlist) do
253 for i, e in ipairs(_resolve_deps(config)) do
254 if not util.contains(reloadlist, e) then
255 reloadlist[#reloadlist+1] = e
256 end
257 end
258 end
259
260 return reloadlist
261 end
262
263 --- Create a sub-state of this cursor. The sub-state is tied to the parent
264 -- curser, means it the parent unloads or loads configs, the sub state will
265 -- do so as well.
266 -- @return UCI state cursor tied to the parent cursor
267 function Cursor.substate(self)
268 Cursor._substates = Cursor._substates or { }
269 Cursor._substates[self] = Cursor._substates[self] or cursor_state()
270 return Cursor._substates[self]
271 end
272
273 local _load = Cursor.load
274 function Cursor.load(self, ...)
275 if Cursor._substates and Cursor._substates[self] then
276 _load(Cursor._substates[self], ...)
277 end
278 return _load(self, ...)
279 end
280
281 local _unload = Cursor.unload
282 function Cursor.unload(self, ...)
283 if Cursor._substates and Cursor._substates[self] then
284 _unload(Cursor._substates[self], ...)
285 end
286 return _unload(self, ...)
287 end
288
289
290 --- Add an anonymous section.
291 -- @class function
292 -- @name Cursor.add
293 -- @param config UCI config
294 -- @param type UCI section type
295 -- @return Name of created section
296
297 --- Get a table of saved but uncommitted changes.
298 -- @class function
299 -- @name Cursor.changes
300 -- @param config UCI config
301 -- @return Table of changes
302 -- @see Cursor.save
303
304 --- Commit saved changes.
305 -- @class function
306 -- @name Cursor.commit
307 -- @param config UCI config
308 -- @return Boolean whether operation succeeded
309 -- @see Cursor.revert
310 -- @see Cursor.save
311
312 --- Deletes a section or an option.
313 -- @class function
314 -- @name Cursor.delete
315 -- @param config UCI config
316 -- @param section UCI section name
317 -- @param option UCI option (optional)
318 -- @return Boolean whether operation succeeded
319
320 --- Call a function for every section of a certain type.
321 -- @class function
322 -- @name Cursor.foreach
323 -- @param config UCI config
324 -- @param type UCI section type
325 -- @param callback Function to be called
326 -- @return Boolean whether operation succeeded
327
328 --- Get a section type or an option
329 -- @class function
330 -- @name Cursor.get
331 -- @param config UCI config
332 -- @param section UCI section name
333 -- @param option UCI option (optional)
334 -- @return UCI value
335
336 --- Get all sections of a config or all values of a section.
337 -- @class function
338 -- @name Cursor.get_all
339 -- @param config UCI config
340 -- @param section UCI section name (optional)
341 -- @return Table of UCI sections or table of UCI values
342
343 --- Manually load a config.
344 -- @class function
345 -- @name Cursor.load
346 -- @param config UCI config
347 -- @return Boolean whether operation succeeded
348 -- @see Cursor.save
349 -- @see Cursor.unload
350
351 --- Revert saved but uncommitted changes.
352 -- @class function
353 -- @name Cursor.revert
354 -- @param config UCI config
355 -- @return Boolean whether operation succeeded
356 -- @see Cursor.commit
357 -- @see Cursor.save
358
359 --- Saves changes made to a config to make them committable.
360 -- @class function
361 -- @name Cursor.save
362 -- @param config UCI config
363 -- @return Boolean whether operation succeeded
364 -- @see Cursor.load
365 -- @see Cursor.unload
366
367 --- Set a value or create a named section.
368 -- @class function
369 -- @name Cursor.set
370 -- @param config UCI config
371 -- @param section UCI section name
372 -- @param option UCI option or UCI section type
373 -- @param value UCI value or nil if you want to create a section
374 -- @return Boolean whether operation succeeded
375
376 --- Get the configuration directory.
377 -- @class function
378 -- @name Cursor.get_confdir
379 -- @return Configuration directory
380
381 --- Get the directory for uncomitted changes.
382 -- @class function
383 -- @name Cursor.get_savedir
384 -- @return Save directory
385
386 --- Set the configuration directory.
387 -- @class function
388 -- @name Cursor.set_confdir
389 -- @param directory UCI configuration directory
390 -- @return Boolean whether operation succeeded
391
392 --- Set the directory for uncommited changes.
393 -- @class function
394 -- @name Cursor.set_savedir
395 -- @param directory UCI changes directory
396 -- @return Boolean whether operation succeeded
397
398 --- Discard changes made to a config.
399 -- @class function
400 -- @name Cursor.unload
401 -- @param config UCI config
402 -- @return Boolean whether operation succeeded
403 -- @see Cursor.load
404 -- @see Cursor.save