libs/core: Create get_first() in uci model
[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 val == "enabled")
188                         end
189
190                         if val ~= nil then
191                                 rv = val
192                                 return false
193                         end
194                 end)
195
196         return rv
197 end
198
199 --- Set given values as list.
200 -- @param config        UCI config
201 -- @param section       UCI section name
202 -- @param option        UCI option
203 -- @param value         UCI value
204 -- @return                      Boolean whether operation succeeded
205 function Cursor.set_list(self, config, section, option, value)
206         if config and section and option then
207                 return self:set(
208                         config, section, option,
209                         ( type(value) == "table" and value or { value } )
210                 )
211         end
212         return false
213 end
214
215 -- Return a list of initscripts affected by configuration changes.
216 function Cursor._affected(self, configlist)
217         configlist = type(configlist) == "table" and configlist or {configlist}
218
219         local c = cursor()
220         c:load("ucitrack")
221
222         -- Resolve dependencies
223         local reloadlist = {}
224
225         local function _resolve_deps(name)
226                 local reload = {name}
227                 local deps = {}
228
229                 c:foreach("ucitrack", name,
230                         function(section)
231                                 if section.affects then
232                                         for i, aff in ipairs(section.affects) do
233                                                 deps[#deps+1] = aff
234                                         end
235                                 end
236                         end)
237
238                 for i, dep in ipairs(deps) do
239                         for j, add in ipairs(_resolve_deps(dep)) do
240                                 reload[#reload+1] = add
241                         end
242                 end
243
244                 return reload
245         end
246
247         -- Collect initscripts
248         for j, config in ipairs(configlist) do
249                 for i, e in ipairs(_resolve_deps(config)) do
250                         if not util.contains(reloadlist, e) then
251                                 reloadlist[#reloadlist+1] = e
252                         end
253                 end
254         end
255
256         return reloadlist
257 end
258
259 --- Create a sub-state of this cursor. The sub-state is tied to the parent
260 -- curser, means it the parent unloads or loads configs, the sub state will
261 -- do so as well.
262 -- @return                      UCI state cursor tied to the parent cursor
263 function Cursor.substate(self)
264         Cursor._substates = Cursor._substates or { }
265         Cursor._substates[self] = Cursor._substates[self] or cursor_state()
266         return Cursor._substates[self]
267 end
268
269 local _load = Cursor.load
270 function Cursor.load(self, ...)
271         if Cursor._substates and Cursor._substates[self] then
272                 _load(Cursor._substates[self], ...)
273         end
274         return _load(self, ...)
275 end
276
277 local _unload = Cursor.unload
278 function Cursor.unload(self, ...)
279         if Cursor._substates and Cursor._substates[self] then
280                 _unload(Cursor._substates[self], ...)
281         end
282         return _unload(self, ...)
283 end
284
285
286 --- Add an anonymous section.
287 -- @class function
288 -- @name Cursor.add
289 -- @param config        UCI config
290 -- @param type          UCI section type
291 -- @return                      Name of created section
292
293 --- Get a table of saved but uncommitted changes.
294 -- @class function
295 -- @name Cursor.changes
296 -- @param config        UCI config
297 -- @return                      Table of changes
298 -- @see Cursor.save
299
300 --- Commit saved changes.
301 -- @class function
302 -- @name Cursor.commit
303 -- @param config        UCI config
304 -- @return                      Boolean whether operation succeeded
305 -- @see Cursor.revert
306 -- @see Cursor.save
307
308 --- Deletes a section or an option.
309 -- @class function
310 -- @name Cursor.delete
311 -- @param config        UCI config
312 -- @param section       UCI section name
313 -- @param option        UCI option (optional)
314 -- @return                      Boolean whether operation succeeded
315
316 --- Call a function for every section of a certain type.
317 -- @class function
318 -- @name Cursor.foreach
319 -- @param config        UCI config
320 -- @param type          UCI section type
321 -- @param callback      Function to be called
322 -- @return                      Boolean whether operation succeeded
323
324 --- Get a section type or an option
325 -- @class function
326 -- @name Cursor.get
327 -- @param config        UCI config
328 -- @param section       UCI section name
329 -- @param option        UCI option (optional)
330 -- @return                      UCI value
331
332 --- Get all sections of a config or all values of a section.
333 -- @class function
334 -- @name Cursor.get_all
335 -- @param config        UCI config
336 -- @param section       UCI section name (optional)
337 -- @return                      Table of UCI sections or table of UCI values
338
339 --- Manually load a config.
340 -- @class function
341 -- @name Cursor.load
342 -- @param config        UCI config
343 -- @return                      Boolean whether operation succeeded
344 -- @see Cursor.save
345 -- @see Cursor.unload
346
347 --- Revert saved but uncommitted changes.
348 -- @class function
349 -- @name Cursor.revert
350 -- @param config        UCI config
351 -- @return                      Boolean whether operation succeeded
352 -- @see Cursor.commit
353 -- @see Cursor.save
354
355 --- Saves changes made to a config to make them committable.
356 -- @class function
357 -- @name Cursor.save
358 -- @param config        UCI config
359 -- @return                      Boolean whether operation succeeded
360 -- @see Cursor.load
361 -- @see Cursor.unload
362
363 --- Set a value or create a named section.
364 -- @class function
365 -- @name Cursor.set
366 -- @param config        UCI config
367 -- @param section       UCI section name
368 -- @param option        UCI option or UCI section type
369 -- @param value         UCI value or nil if you want to create a section
370 -- @return                      Boolean whether operation succeeded
371
372 --- Get the configuration directory.
373 -- @class function
374 -- @name Cursor.get_confdir
375 -- @return                      Configuration directory
376
377 --- Get the directory for uncomitted changes.
378 -- @class function
379 -- @name Cursor.get_savedir
380 -- @return                      Save directory
381
382 --- Set the configuration directory.
383 -- @class function
384 -- @name Cursor.set_confdir
385 -- @param directory     UCI configuration directory
386 -- @return                      Boolean whether operation succeeded
387
388 --- Set the directory for uncommited changes.
389 -- @class function
390 -- @name Cursor.set_savedir
391 -- @param directory     UCI changes directory
392 -- @return                      Boolean whether operation succeeded
393
394 --- Discard changes made to a config.
395 -- @class function
396 -- @name Cursor.unload
397 -- @param config        UCI config
398 -- @return                      Boolean whether operation succeeded
399 -- @see Cursor.load
400 -- @see Cursor.save