* CBI: Changed parser to list UCI sections in order of their appearance
[project/luci.git] / core / src / ffluci / model / uci.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
11 ToDo: Reimplement in Lua
12
13 FileId:
14 $Id$
15
16 License:
17 Copyright 2008 Steven Barth <steven@midlink.org>
18
19 Licensed under the Apache License, Version 2.0 (the "License");
20 you may not use this file except in compliance with the License.
21 You may obtain a copy of the License at
22
23 http://www.apache.org/licenses/LICENSE-2.0
24
25 Unless required by applicable law or agreed to in writing, software
26 distributed under the License is distributed on an "AS IS" BASIS,
27 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28 See the License for the specific language governing permissions and
29 limitations under the License.
30
31 ]]--
32 module("ffluci.model.uci", package.seeall)
33 require("ffluci.util")
34 require("ffluci.fs")
35 require("ffluci.sys")
36
37 -- The OS uci command
38 ucicmd = "uci"
39
40 -- Session class
41 Session = ffluci.util.class()
42
43 -- Session constructor
44 function Session.__init__(self, path, uci)
45 uci = uci or ucicmd
46 if path then
47 self.ucicmd = uci .. " -P " .. path
48 else
49 self.ucicmd = uci
50 end
51 end
52
53 -- The default Session
54 local default = Session()
55
56 -- Wrapper for "uci add"
57 function Session.add(self, config, section_type)
58 return self:_uci("add " .. _path(config) .. " " .. _path(section_type))
59 end
60
61 function add(...)
62 return default:add(...)
63 end
64
65
66 -- Wrapper for "uci changes"
67 function Session.changes(self, config)
68 return self:_uci("changes " .. _path(config))
69 end
70
71 function changes(...)
72 return default:changes(...)
73 end
74
75
76 -- Wrapper for "uci commit"
77 function Session.commit(self, config)
78 return self:_uci2("commit " .. _path(config))
79 end
80
81 function commit(...)
82 return default:commit(...)
83 end
84
85
86 -- Wrapper for "uci del"
87 function Session.del(self, config, section, option)
88 return self:_uci2("del " .. _path(config, section, option))
89 end
90
91 function del(...)
92 return default:del(...)
93 end
94
95
96 -- Wrapper for "uci get"
97 function Session.get(self, config, section, option)
98 return self:_uci("get " .. _path(config, section, option))
99 end
100
101 function get(...)
102 return default:get(...)
103 end
104
105
106 -- Wrapper for "uci revert"
107 function Session.revert(self, config)
108 return self:_uci2("revert " .. _path(config))
109 end
110
111 function revert(...)
112 return default:revert(...)
113 end
114
115
116 -- Wrapper for "uci show"
117 function Session.show(self, config)
118 return self:_uci3("show " .. _path(config))
119 end
120
121 function show(...)
122 return default:show(...)
123 end
124
125
126 -- Wrapper for "uci set"
127 function Session.set(self, config, section, option, value)
128 return self:_uci2("set " .. _path(config, section, option, value))
129 end
130
131 function set(...)
132 return default:set(...)
133 end
134
135
136 -- Internal functions --
137
138 function Session._uci(self, cmd)
139 local res = ffluci.sys.exec(self.ucicmd .. " 2>/dev/null " .. cmd)
140
141 if res:len() == 0 then
142 return nil
143 else
144 return res:sub(1, res:len()-1)
145 end
146 end
147
148 function Session._uci2(self, cmd)
149 local res = ffluci.sys.exec(self.ucicmd .. " 2>&1 " .. cmd)
150
151 if res:len() > 0 then
152 return false, res
153 else
154 return true
155 end
156 end
157
158 function Session._uci3(self, cmd)
159 local res = ffluci.sys.execl(self.ucicmd .. " 2>&1 " .. cmd)
160 if res[1] and res[1]:sub(1, self.ucicmd:len()+1) == self.ucicmd..":" then
161 return nil, res[1]
162 end
163
164 tbl = {}
165
166 for k,line in pairs(res) do
167 c, s, t = line:match("^([^.]-)%.([^.]-)=(.-)$")
168 if c then
169 tbl[c] = tbl[c] or {}
170 tbl[c][".order"] = tbl[c][".order"] or {}
171
172 tbl[c][s] = {}
173 table.insert(tbl[c][".order"], s)
174 tbl[c][s][".type"] = t
175 end
176
177 c, s, o, v = line:match("^([^.]-)%.([^.]-)%.([^.]-)=(.-)$")
178 if c then
179 tbl[c][s][o] = v
180 end
181 end
182
183 return tbl
184 end
185
186 -- Build path (config.section.option=value) and prevent command injection
187 function _path(...)
188 local result = ""
189
190 -- Not using ipairs because it is not reliable in case of nil arguments
191 arg.n = nil
192 for k,v in pairs(arg) do
193 if v then
194 v = tostring(v)
195 if k == 1 then
196 result = "'" .. v:gsub("['.]", "") .. "'"
197 elseif k < 4 then
198 result = result .. ".'" .. v:gsub("['.]", "") .. "'"
199 elseif k == 4 then
200 result = result .. "='" .. v:gsub("'", "") .. "'"
201 end
202 end
203 end
204 return result
205 end