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