5faffe548636bd1b29c696a93ed80dde180fc308
[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:_uci3("changes " .. _path(config))
65 end
66
67 function change(...)
68 return default:change(...)
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 get"
83 function Session.get(self, config, section, option)
84 return self:_uci("get " .. _path(config, section, option))
85 end
86
87 function get(...)
88 return default:get(...)
89 end
90
91
92 -- Wrapper for "uci revert"
93 function Session.revert(self, config)
94 return self:_uci2("revert " .. _path(config))
95 end
96
97 function revert(...)
98 return self:revert(...)
99 end
100
101
102 -- Wrapper for "uci show"
103 function Session.show(self, config)
104 return self:_uci3("show " .. _path(config))
105 end
106
107 function show(...)
108 return default:show(...)
109 end
110
111
112 -- Wrapper for "uci set"
113 function Session.set(self, config, section, option, value)
114 return self:_uci2("set " .. _path(config, section, option, value))
115 end
116
117 function set(...)
118 return default:set(...)
119 end
120
121
122 -- Internal functions --
123
124 function Session._uci(self, cmd)
125 local res = ffluci.util.exec(self.ucicmd .. " 2>/dev/null " .. cmd)
126
127 if res:len() == 0 then
128 return nil
129 else
130 return res:sub(1, res:len()-1)
131 end
132 end
133
134 function Session._uci2(self, cmd)
135 local res = ffluci.util.exec(self.ucicmd .. " 2>&1 " .. cmd)
136
137 if res:len() > 0 then
138 return false, res
139 else
140 return true
141 end
142 end
143
144 function Session._uci3(self, cmd)
145 local res = ffluci.util.execl(self.ucicmd .. " 2>&1 " .. cmd)
146 if res[1]:sub(1, ucicmd:len() + 1) == ucicmd .. ":" then
147 return nil, res[1]
148 end
149
150 table = {}
151
152 for k,line in pairs(res) do
153 c, s, t = line:match("^([^.]-)%.([^.]-)=(.-)$")
154 if c then
155 table[c] = table[c] or {}
156 table[c][s] = {}
157 table[c][s][".type"] = t
158 end
159
160 c, s, o, v = line:match("^([^.]-)%.([^.]-)%.([^.]-)=(.-)$")
161 if c then
162 table[c][s][o] = v
163 end
164 end
165
166 return table
167 end
168
169 -- Build path (config.section.option=value) and prevent command injection
170 function _path(...)
171 local result = ""
172
173 -- Not using ipairs because it is not reliable in case of nil arguments
174 arg.n = nil
175 for k,v in pairs(arg) do
176 if k == 1 then
177 result = "'" .. v:gsub("['.]", "") .. "'"
178 elseif k < 4 then
179 result = result .. ".'" .. v:gsub("['.]", "") .. "'"
180 elseif k == 4 then
181 result = result .. "='" .. v:gsub("'", "") .. "'"
182 end
183 end
184 return result
185 end