1 module("uci.trigger", package.seeall)
5 local path = "/lib/config/trigger"
9 function load_modules()
10 if triggers ~= nil then
18 local modules = posix.glob(path .. "/*.lua")
19 if modules == nil then
22 local oldpath = package.path
23 package.path = path .. "/?.lua"
24 for i, v in ipairs(modules) do
25 pcall(require(string.gsub(v, path .. "/(%w+)%.lua$", "%1")))
27 package.path = oldpath
30 function check_table(table, name)
31 if table[name] == nil then
37 function get_table_val(val, vtype)
38 if type(val) == (vtype or "string") then
40 elseif type(val) == "table" then
46 function get_name_list(name)
47 return get_table_val(name or ".all")
50 function add_trigger_option(list, t)
51 local name = get_name_list(t.option)
52 for i, n in ipairs(name) do
53 option = check_table(list, n)
54 table.insert(option, t)
58 function add_trigger_section(list, t)
59 local name = get_name_list(t.section)
60 for i, n in ipairs(name) do
61 section = check_table(list, n)
62 add_trigger_option(section, t)
66 function check_insert_triggers(dest, list, tuple)
70 for i, t in ipairs(list) do
72 if type(t.check) == "function" then
81 function find_section_triggers(tlist, pos, tuple)
85 check_insert_triggers(tlist, pos[".all"], tuple)
87 check_insert_triggers(tlist, pos[tuple.option], tuple)
91 function check_recursion(name, seen)
103 function find_recursive_depends(list, name, seen)
104 seen = check_recursion(name, seen)
108 local bt = get_table_val(triggers.list[name].belongs_to) or {}
109 for i, n in ipairs(bt) do
110 table.insert(list, n)
111 find_recursive_depends(list, n, seen)
115 function check_trigger_depth(list, name)
126 return check_trigger_depth(list, n)
129 function find_triggers(tuple)
130 local pos = triggers.uci[tuple.package]
136 find_section_triggers(tlist, pos[".all"], tuple)
137 find_section_triggers(tlist, pos[tuple.section[".type"]], tuple)
139 for n, t in pairs(tlist) do
141 find_recursive_depends(dep, t.id)
142 for i, depname in ipairs(dep) do
143 check_trigger_depth(tlist, depname)
148 for n, t in pairs(tlist) do
150 table.insert(nlist, t)
157 function reset_state()
158 assert(io.open("/var/run/uci_trigger", "w")):close()
160 tctx:unload("uci_trigger")
164 function load_state()
165 -- make sure the config file exists before we attempt to load it
166 -- uci doesn't like loading nonexistent config files
167 local f = assert(io.open("/var/run/uci_trigger", "a")):close()
172 tctx:unload("uci_trigger")
176 assert(tctx:load("/var/run/uci_trigger"))
177 tctx:foreach("uci_trigger", "trigger",
179 trigger = triggers.list[section[".name"]]
180 if trigger == nil then
185 triggers.active[trigger.id] = active
187 local s = get_table_val(section["sections"]) or {}
188 for i, v in ipairs(s) do
195 function get_names(list)
197 for name, val in pairs(list) do
199 table.insert(slist, name)
205 function check_cancel(name, seen)
206 local t = triggers.list[name]
207 local dep = get_table_val(t.belongs_to)
208 seen = check_recursion(name, seen)
210 if not t or not dep or not seen then
214 for i, v in ipairs(dep) do
215 -- only cancel triggers for all sections
216 -- if both the current and the parent trigger
218 local section_only = false
219 if t.section_only then
220 local tdep = triggers.list[v]
222 section_only = tdep.section_only
226 if check_cancel(v, seen) then
229 if triggers.active[v] then
231 for n, active in pairs(triggers.active[v]) do
232 triggers.active[name][n] = false
242 -- trigger api functions
245 for i,t in ipairs(ts) do
246 triggers.list[t.id] = t
249 local package = check_table(triggers.uci, t.package)
250 add_trigger_section(package, t)
251 triggers.list[t.id] = t
256 function save_trigger(name)
257 if triggers.active[name] then
258 local slist = get_names(triggers.active[name])
260 tctx:set("uci_trigger", name, "sections", slist)
263 tctx:delete("uci_trigger", name)
267 function set(data, cursor)
269 if cursor == nil then
270 cursor = tmp_cursor or uci.cursor()
271 tmp_cursor = uci.cursor
280 assert(cursor:load(tuple.package))
283 local section = cursor:get_all(tuple.package, tuple.section)
284 if (section == nil) then
285 if option ~= nil then
291 if tuple.section == nil then
293 section[".anonymous"] = true
295 section[".name"] = tuple.section
297 tuple.section = section
299 local ts = find_triggers(tuple)
300 for i, t in ipairs(ts) do
301 local active = triggers.active[t.id]
304 triggers.active[t.id] = active
305 tctx:set("uci_trigger", t.id, "trigger")
307 if section[".name"] then
308 active[section[".name"]] = true
312 tctx:save("uci_trigger")
315 function get_description(trigger, sections)
316 if not trigger.title then
319 local desc = trigger.title
320 if trigger.section_only and sections and #sections > 0 then
321 desc = desc .. " (" .. table.concat(sections, ", ") .. ")"
326 function get_active()
329 if triggers == nil then
332 for name, val in pairs(triggers.active) do
333 if val and not check_cancel(name) then
335 for name, active in pairs(triggers.active[name]) do
337 table.insert(sections, name)
340 table.insert(slist, { triggers.list[name], sections })
346 function set_active(trigger, sections)
347 if triggers == nil then
350 if not triggers.list[trigger] then
353 if triggers.active[trigger] == nil then
354 tctx:set("uci_trigger", trigger, "trigger")
355 triggers.active[trigger] = {}
357 local active = triggers.active[trigger]
358 if triggers.list[trigger].section_only or sections ~= nil then
359 for i, t in ipairs(sections) do
360 triggers.active[trigger][t] = true
363 save_trigger(trigger)
364 tctx:save("uci_trigger")
367 function clear_active(trigger, sections)
368 if triggers == nil then
371 if triggers.list[trigger] == nil or triggers.active[trigger] == nil then
374 local active = triggers.active[trigger]
375 if not triggers.list[trigger].section_only or sections == nil then
376 triggers.active[trigger] = nil
378 for i, t in ipairs(sections) do
379 triggers.active[trigger][t] = false
382 save_trigger(trigger)
383 tctx:save("uci_trigger")
390 for i, t in ipairs(ts) do
392 local sections = t[2]
393 local actions = get_table_val(trigger.action, "function") or {}
394 for ai, a in ipairs(actions) do
395 if not trigger.section_only then
398 for si, s in ipairs(sections) do
400 tctx:delete("uci_trigger", trigger.id)
401 tctx:save("uci_trigger")
410 function system_command(arg)
413 return os.execute(cmd:format(arg)) == 0
417 function service_restart(arg)
418 return system_command("/etc/init.d/" .. arg .. " restart")