94a385c7e1c17795ee3409ca7bb31525ae8f8804
[project/luci.git] / 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]:sub(1, ucicmd:len() + 1) == ucicmd .. ":" then
161                 return nil, res[1]
162         end
163
164         table = {}
165         
166         for k,line in pairs(res) do
167                 c, s, t = line:match("^([^.]-)%.([^.]-)=(.-)$")
168                 if c then
169                         table[c] = table[c] or {}
170                         table[c][s] = {}
171                         table[c][s][".type"] = t
172                 end
173         
174                 c, s, o, v = line:match("^([^.]-)%.([^.]-)%.([^.]-)=(.-)$")
175                 if c then
176                         table[c][s][o] = v
177                 end
178         end
179         
180         return table
181 end
182
183 -- Build path (config.section.option=value) and prevent command injection
184 function _path(...)
185         local result = ""
186         
187         -- Not using ipairs because it is not reliable in case of nil arguments
188         arg.n = nil
189         for k,v in pairs(arg) do
190                 if v then
191                         v = tostring(v)
192                         if k == 1 then
193                                 result = "'" .. v:gsub("['.]", "") .. "'"
194                         elseif k < 4 then
195                                 result = result .. ".'" .. v:gsub("['.]", "") .. "'"
196                         elseif k == 4 then
197                                 result = result .. "='" .. v:gsub("'", "") .. "'"
198                         end
199                 end
200         end
201         return result
202 end