(no commit message)
[project/luci.git] / core / src / ffluci / model / uci / wrapper.lua
1 --[[
2 FFLuCI - UCI wrapper library
3
4 Description:
5 Wrapper for the /sbin/uci application, syntax of implemented functions
6 is comparable to the syntax of the uci application
7
8 Any return value of false or nil can be interpreted as an error
9
10 FileId:
11 $Id$
12
13 License:
14 Copyright 2008 Steven Barth <steven@midlink.org>
15
16 Licensed under the Apache License, Version 2.0 (the "License");
17 you may not use this file except in compliance with the License.
18 You may obtain a copy of the License at 
19
20         http://www.apache.org/licenses/LICENSE-2.0 
21
22 Unless required by applicable law or agreed to in writing, software
23 distributed under the License is distributed on an "AS IS" BASIS,
24 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25 See the License for the specific language governing permissions and
26 limitations under the License.
27
28 ]]--
29
30 module("ffluci.model.uci.wrapper", package.seeall)
31
32 require("ffluci.util")
33 require("ffluci.sys")
34
35 -- Session class
36 Session = ffluci.util.class()
37
38 -- Session constructor
39 function Session.__init__(self, savedir)
40         self.ucicmd = savedir and "uci -P " .. savedir or "uci"
41 end
42
43 function Session.add(self, config, section_type)
44         return self:_uci("add " .. _path(config) .. " " .. _path(section_type))
45 end
46
47 function Session.changes(self, config)
48         return self:_uci("changes " .. _path(config))
49 end
50
51 function Session.commit(self, config)
52         return self:_uci2("commit " .. _path(config))
53 end
54
55 function Session.del(self, config, section, option)
56         return self:_uci2("del " .. _path(config, section, option))
57 end
58
59 function Session.get(self, config, section, option)
60         return self:_uci("get " .. _path(config, section, option))
61 end
62
63 function Session.revert(self, config)
64         return self:_uci2("revert " .. _path(config))
65 end
66
67 function Session.sections(self, config) 
68         if not config then
69                 return nil
70         end
71         
72         local r1, r2 = self:_uci3("show " .. _path(config))
73         if type(r1) == "table" then
74                 return r1, r2
75         else
76                 return nil, r2
77         end
78 end
79
80 function Session.set(self, config, section, option, value)
81         return self:_uci2("set " .. _path(config, section, option, value))
82 end
83
84 function Session.synchronize(self) end
85
86 -- Dummy transaction functions
87
88 function Session.t_load(self) end
89 function Session.t_save(self) end
90
91 Session.t_add = Session.add
92 Session.t_commit = Session.commit
93 Session.t_del = Session.del
94 Session.t_get = Session.get
95 Session.t_revert = Session.revert
96 Session.t_sections = Session.sections
97 Session.t_set = Session.set
98
99
100
101
102
103 -- Internal functions --
104
105
106 function Session._uci(self, cmd)
107         local res = ffluci.sys.exec(self.ucicmd .. " 2>/dev/null " .. cmd)
108         
109         if res:len() == 0 then
110                 return nil
111         else
112                 return res:sub(1, res:len()-1)
113         end     
114 end
115
116 function Session._uci2(self, cmd)
117         local res = ffluci.sys.exec(self.ucicmd .. " 2>&1 " .. cmd)
118         
119         if res:len() > 0 then
120                 return false, res
121         else
122                 return true
123         end     
124 end
125
126 function Session._uci3(self, cmd)
127         local res = ffluci.sys.execl(self.ucicmd .. " 2>&1 " .. cmd)
128         if res[1] and res[1]:sub(1, self.ucicmd:len()+1) == self.ucicmd..":" then
129                 return nil, res[1]
130         end
131
132         local tbl = {}
133         local ord = {}
134
135         for k,line in pairs(res) do
136                 c, s, t = line:match("^([^.]-)%.([^.]-)=(.-)$")
137                 if c then
138                         tbl[s] = {}
139                         table.insert(ord, s)
140                         tbl[s][".type"] = t
141                 end
142         
143                 c, s, o, v = line:match("^([^.]-)%.([^.]-)%.([^.]-)=(.-)$")
144                 if c then
145                         tbl[s][o] = v
146                 end
147         end
148         
149         return tbl, ord
150 end
151
152 -- Build path (config.section.option=value) and prevent command injection
153 function _path(...)
154         local result = ""
155         
156         -- Not using ipairs because it is not reliable in case of nil arguments
157         arg.n = nil
158         for k,v in pairs(arg) do
159                 if v then
160                         v = tostring(v)
161                         if k == 1 then
162                                 result = "'" .. v:gsub("['.]", "") .. "'"
163                         elseif k < 4 then
164                                 result = result .. ".'" .. v:gsub("['.]", "") .. "'"
165                         elseif k == 4 then
166                                 result = result .. "='" .. v:gsub("'", "") .. "'"
167                         end
168                 end
169         end
170         return result
171 end