* CBI update
[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 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 module("ffluci.model.uci", package.seeall)
30 require("ffluci.util")
31 require("ffluci.fs")
32
33 -- The OS uci command
34 ucicmd = "uci"
35
36 -- Session class
37 Session = ffluci.util.class()
38
39 -- Session constructor
40 function Session.__init__(self, path, uci)
41         uci = uci or ucicmd
42         if path then
43                 self.ucicmd = uci .. " -P " .. path 
44         else
45                 self.ucicmd = uci
46         end
47 end
48
49 -- The default Session
50 local default = Session()
51
52 -- Wrapper for "uci add"
53 function Session.add(self, config, section_type)
54         return self:_uci("add " .. _path(config) .. " " .. _path(section_type))
55 end
56
57 function add(...)
58         return default:add(...)
59 end
60
61
62 -- Wrapper for "uci changes"
63 function Session.changes(self, config)
64         return self:_uci("changes " .. _path(config))
65 end
66
67 function changes(...)
68         return default:changes(...)
69 end
70
71
72 -- Wrapper for "uci commit"
73 function Session.commit(self, config)
74         return self:_uci2("commit " .. _path(config))
75 end
76
77 function commit(...)
78         return default:commit(...)
79 end
80
81
82 -- Wrapper for "uci del"
83 function Session.del(self, config, section, option)
84         return self:_uci2("del " .. _path(config, section, option))
85 end
86
87 function del(...)
88         return default:del(...)
89 end
90
91
92 -- Wrapper for "uci get"
93 function Session.get(self, config, section, option)
94         return self:_uci("get " .. _path(config, section, option))
95 end
96
97 function get(...)
98         return default:get(...)
99 end
100
101
102 -- Wrapper for "uci revert"
103 function Session.revert(self, config)
104         return self:_uci2("revert " .. _path(config))
105 end
106
107 function revert(...)
108         return default:revert(...)
109 end
110
111
112 -- Wrapper for "uci show"
113 function Session.show(self, config)
114         return self:_uci3("show " .. _path(config))
115 end
116
117 function show(...)
118         return default:show(...)
119 end
120
121
122 -- Wrapper for "uci set"
123 function Session.set(self, config, section, option, value)
124         return self:_uci2("set " .. _path(config, section, option, value))
125 end
126
127 function set(...)
128         return default:set(...)
129 end
130
131
132 -- Internal functions --
133
134 function Session._uci(self, cmd)
135         local res = ffluci.util.exec(self.ucicmd .. " 2>/dev/null " .. cmd)
136         
137         if res:len() == 0 then
138                 return nil
139         else
140                 return res:sub(1, res:len()-1)
141         end     
142 end
143
144 function Session._uci2(self, cmd)
145         local res = ffluci.util.exec(self.ucicmd .. " 2>&1 " .. cmd)
146         
147         if res:len() > 0 then
148                 return false, res
149         else
150                 return true
151         end     
152 end
153
154 function Session._uci3(self, cmd)
155         local res = ffluci.util.execl(self.ucicmd .. " 2>&1 " .. cmd)
156         if res[1]:sub(1, ucicmd:len() + 1) == ucicmd .. ":" then
157                 return nil, res[1]
158         end
159
160         table = {}
161         
162         for k,line in pairs(res) do
163                 c, s, t = line:match("^([^.]-)%.([^.]-)=(.-)$")
164                 if c then
165                         table[c] = table[c] or {}
166                         table[c][s] = {}
167                         table[c][s][".type"] = t
168                 end
169         
170                 c, s, o, v = line:match("^([^.]-)%.([^.]-)%.([^.]-)=(.-)$")
171                 if c then
172                         table[c][s][o] = v
173                 end
174         end
175         
176         return table
177 end
178
179 -- Build path (config.section.option=value) and prevent command injection
180 function _path(...)
181         local result = ""
182         
183         -- Not using ipairs because it is not reliable in case of nil arguments
184         arg.n = nil
185         for k,v in pairs(arg) do
186                 if v then
187                         v = tostring(v)
188                         if k == 1 then
189                                 result = "'" .. v:gsub("['.]", "") .. "'"
190                         elseif k < 4 then
191                                 result = result .. ".'" .. v:gsub("['.]", "") .. "'"
192                         elseif k == 4 then
193                                 result = result .. "='" .. v:gsub("'", "") .. "'"
194                         end
195                 end
196         end
197         return result
198 end