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