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