75a898acbd73a6c90665dd74ffe5b48f5db99556
[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 local state   = Session("/var/state")
56
57 -- The state Session
58 function StateSession()
59         return state
60 end
61
62
63 -- Wrapper for "uci add"
64 function Session.add(self, config, section_type)
65         return self:_uci("add " .. _path(config) .. " " .. _path(section_type))
66 end
67
68 function add(...)
69         return default:add(...)
70 end
71
72
73 -- Wrapper for "uci changes"
74 function Session.changes(self, config)
75         return self:_uci("changes " .. _path(config))
76 end
77
78 function changes(...)
79         return default:changes(...)
80 end
81
82
83 -- Wrapper for "uci commit"
84 function Session.commit(self, config)
85         return self:_uci2("commit " .. _path(config))
86 end
87
88 function commit(...)
89         return default:commit(...)
90 end
91
92
93 -- Wrapper for "uci del"
94 function Session.del(self, config, section, option)
95         return self:_uci2("del " .. _path(config, section, option))
96 end
97
98 function del(...)
99         return default:del(...)
100 end
101
102
103 -- Wrapper for "uci get"
104 function Session.get(self, config, section, option)
105         return self:_uci("get " .. _path(config, section, option))
106 end
107
108 function get(...)
109         return default:get(...)
110 end
111
112
113 -- Wrapper for "uci revert"
114 function Session.revert(self, config)
115         return self:_uci2("revert " .. _path(config))
116 end
117
118 function revert(...)
119         return default:revert(...)
120 end
121
122
123 -- Wrapper for "uci show"
124 function Session.show(self, config, ...)
125         return self:_uci3("show " .. _path(config), ...)
126 end
127
128 function show(...)
129         return default:show(...)
130 end
131
132
133 -- Wrapper for "uci set"
134 function Session.set(self, config, section, option, value)
135         return self:_uci2("set " .. _path(config, section, option, value))
136 end
137
138 function set(...)
139         return default:set(...)
140 end
141
142
143 -- Internal functions --
144
145 function Session._uci(self, cmd)
146         local res = ffluci.sys.exec(self.ucicmd .. " 2>/dev/null " .. cmd)
147         
148         if res:len() == 0 then
149                 return nil
150         else
151                 return res:sub(1, res:len()-1)
152         end     
153 end
154
155 function Session._uci2(self, cmd)
156         local res = ffluci.sys.exec(self.ucicmd .. " 2>&1 " .. cmd)
157         
158         if res:len() > 0 then
159                 return false, res
160         else
161                 return true
162         end     
163 end
164
165 function Session._uci3(self, cmd, raw)
166         local res = ffluci.sys.execl(self.ucicmd .. " 2>&1 " .. cmd)
167         if res[1] and res[1]:sub(1, self.ucicmd:len()+1) == self.ucicmd..":" then
168                 return nil, res[1]
169         end
170         
171         if raw then
172                 return table.concat(res, "\n")
173         end
174
175         tbl = {}
176
177         for k,line in pairs(res) do
178                 c, s, t = line:match("^([^.]-)%.([^.]-)=(.-)$")
179                 if c then
180                         tbl[c] = tbl[c] or {}
181                         tbl[c][".order"] = tbl[c][".order"] or {}
182                         
183                         tbl[c][s] = {}
184                         table.insert(tbl[c][".order"], s)
185                         tbl[c][s][".type"] = t
186                 end
187         
188                 c, s, o, v = line:match("^([^.]-)%.([^.]-)%.([^.]-)=(.-)$")
189                 if c then
190                         tbl[c][s][o] = v
191                 end
192         end
193         
194         return tbl
195 end
196
197 -- Build path (config.section.option=value) and prevent command injection
198 function _path(...)
199         local result = ""
200         
201         -- Not using ipairs because it is not reliable in case of nil arguments
202         arg.n = nil
203         for k,v in pairs(arg) do
204                 if v then
205                         v = tostring(v)
206                         if k == 1 then
207                                 result = "'" .. v:gsub("['.]", "") .. "'"
208                         elseif k < 4 then
209                                 result = result .. ".'" .. v:gsub("['.]", "") .. "'"
210                         elseif k == 4 then
211                                 result = result .. "='" .. v:gsub("'", "") .. "'"
212                         end
213                 end
214         end
215         return result
216 end