3aa3b5fd1d4312259bfd8bce74586a68ff92b2c6
[project/luci.git] / core / src / 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