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