242 lines
5.9 KiB
Plaintext
242 lines
5.9 KiB
Plaintext
|
#!/usr/bin/lua
|
||
|
--[[
|
||
|
|
||
|
UCI Validation Layer - Command Line Utility
|
||
|
(c) 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net>
|
||
|
(c) 2008 Steven Barth <steven@midlink.org>
|
||
|
|
||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
you may not use this file except in compliance with the License.
|
||
|
You may obtain a copy of the License at
|
||
|
|
||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
||
|
$Id: uvl 4085 2009-01-17 23:51:28Z jow $
|
||
|
|
||
|
]]--
|
||
|
|
||
|
require("luci.uvl")
|
||
|
require("luci.util")
|
||
|
|
||
|
|
||
|
function getopt( arg, options )
|
||
|
options = options or ""
|
||
|
local tab = {}
|
||
|
local args = {}
|
||
|
for k, v in ipairs(arg) do
|
||
|
if v:sub(1, 2) == "--" then
|
||
|
local x = v:find( "=", 1, true )
|
||
|
if x then
|
||
|
tab[ v:sub( 3, x-1 ) ] = v:sub( x+1 )
|
||
|
else
|
||
|
tab[ v:sub( 3 ) ] = true
|
||
|
end
|
||
|
elseif v:sub( 1, 1 ) == "-" then
|
||
|
local y = 2
|
||
|
local l = #v
|
||
|
local jopt
|
||
|
while ( y <= l ) do
|
||
|
jopt = v:sub( y, y )
|
||
|
if options:find( jopt, 1, true ) then
|
||
|
if y < l then
|
||
|
tab[ jopt ] = v:sub( y+1 )
|
||
|
y = l
|
||
|
else
|
||
|
tab[ jopt ] = arg[ k + 1 ]
|
||
|
arg[ k + 1 ] = ""
|
||
|
end
|
||
|
else
|
||
|
tab[ jopt ] = true
|
||
|
end
|
||
|
y = y + 1
|
||
|
end
|
||
|
elseif #v > 0 then
|
||
|
table.insert(args, v)
|
||
|
end
|
||
|
end
|
||
|
return tab, args
|
||
|
end
|
||
|
|
||
|
function genspec(conf)
|
||
|
require("luci.model.uci")
|
||
|
require("luci.uvl.datatypes")
|
||
|
|
||
|
local uci = luci.model.uci.cursor()
|
||
|
local ok, err = uci:load(conf)
|
||
|
|
||
|
if not ok then
|
||
|
print("Can not load config:", err)
|
||
|
os.exit(1)
|
||
|
else
|
||
|
local function _guess_datatype(v)
|
||
|
if type(v) == "table" then v = v[1] end
|
||
|
|
||
|
for _, type in ipairs({
|
||
|
"boolean", "integer", "float", "ip4addr", "ip6addr",
|
||
|
"macaddr", "directory", "file"
|
||
|
}) do
|
||
|
if luci.uvl.datatypes[type](v) then
|
||
|
return type
|
||
|
end
|
||
|
end
|
||
|
return "string"
|
||
|
end
|
||
|
|
||
|
|
||
|
local co = uci:get_all(conf)
|
||
|
local ct = { }
|
||
|
local ca = { }
|
||
|
local so = { }
|
||
|
local to = { }
|
||
|
|
||
|
-- count section types
|
||
|
for _, section in pairs(co) do
|
||
|
ct[section['.type']] = ( ct[section['.type']] or 0 ) + 1
|
||
|
ca[section['.type']] = section['.anonymous']
|
||
|
so[section['.type']] = so[section['.type']] or { }
|
||
|
to[section['.type']] = to[section['.type']] or { }
|
||
|
|
||
|
for option, value in pairs(section) do
|
||
|
if option:sub(1,1) ~= "." then
|
||
|
so[section['.type']][option] = _guess_datatype(value)
|
||
|
to[section['.type']][option] = ( type(value) == "table" and "list" or "variable" )
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- package name
|
||
|
print( "package %s" % conf )
|
||
|
|
||
|
-- write section schemes
|
||
|
for type, count in luci.util.kspairs(ct) do
|
||
|
print( "\nconfig section" )
|
||
|
print( "\toption name '%s'" % type )
|
||
|
print( "\toption title 'Section %s'" % type )
|
||
|
print( "\toption package '%s'"% conf )
|
||
|
print( "\toption named %s" % ( ca[type] and 'false' or 'true' ) )
|
||
|
print( "\toption unique %s" % ( ct[type] > 1 and 'false' or ( ca[type] and 'false' or 'true' ) ) )
|
||
|
print( "\toption dynamic false" )
|
||
|
print( "\toption required false" )
|
||
|
|
||
|
-- write option schemes
|
||
|
for opt, val in luci.util.kspairs(so[type]) do
|
||
|
print( "\nconfig variable" )
|
||
|
print( "\toption name '%s'" % opt )
|
||
|
print( "\toption title 'Option %s'" % opt )
|
||
|
print( "\toption section '%s.%s'" %{ conf, type } )
|
||
|
print( "\toption datatype '%s'" % so[type][opt] )
|
||
|
|
||
|
if to[type][opt] ~= "variable" then
|
||
|
print( "\toption type '%s'" % to[type][opt] )
|
||
|
end
|
||
|
end
|
||
|
|
||
|
print("")
|
||
|
end
|
||
|
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
local options, arguments = getopt( arg )
|
||
|
|
||
|
if #arguments ~= 2 or options.help then
|
||
|
print([=[
|
||
|
|
||
|
uvl - UCI Validation Layer
|
||
|
$Id: uvl 4085 2009-01-17 23:51:28Z jow $
|
||
|
(c) 2008 Jo-Philipp Wich, Steven Barth
|
||
|
|
||
|
Usage:
|
||
|
uvl --help
|
||
|
uvl [--silent] [--schemedir=DIR] [--configdir=DIR] [--no-strict-sections] \
|
||
|
[--no-strict-options] [--no-strict-validators] [--no-strict-lists] \
|
||
|
{verify|verify-scheme|genspec} config[.section[.option]]
|
||
|
|
||
|
Options:
|
||
|
--help
|
||
|
Display this help message.
|
||
|
|
||
|
--silent
|
||
|
Don't produce any output.
|
||
|
|
||
|
--schemedir=DIR
|
||
|
Use DIR as scheme directory.
|
||
|
|
||
|
--configdir=DIR
|
||
|
Use DIR as config directory.
|
||
|
|
||
|
--no-strict-sections
|
||
|
Don't treat sections found in config but not in scheme as error.
|
||
|
|
||
|
--no-strict-options
|
||
|
Don't treat options found in config but not in scheme as error.
|
||
|
|
||
|
--no-strict-validators
|
||
|
Don't invalidate config if an external validator fails.
|
||
|
|
||
|
--no-strict-lists
|
||
|
Don't invalidate lists that are stored options.
|
||
|
|
||
|
Actions:
|
||
|
verify
|
||
|
Validate given configuration, section or option.
|
||
|
|
||
|
verify-scheme
|
||
|
Validate given scheme against the reference meta scheme.
|
||
|
|
||
|
genspec
|
||
|
Generate a scheme skeleton from given configuration.
|
||
|
]=])
|
||
|
os.exit(255)
|
||
|
elseif arguments[1] == "verify" or arguments[1] == "verify-scheme" then
|
||
|
luci.uvl.STRICT_UNKNOWN_SECTIONS =
|
||
|
( not options['no-strict-sections'] and true or false )
|
||
|
luci.uvl.STRICT_UNKNOWN_OPTIONS =
|
||
|
( not options['no-strict-options'] and true or false )
|
||
|
luci.uvl.STRICT_EXTERNAL_VALIDATORS =
|
||
|
( not options['no-strict-validators'] and true or false )
|
||
|
luci.uvl.STRICT_LIST_TYPE =
|
||
|
( not options['no-strict-lists'] and true or false )
|
||
|
|
||
|
local uvl = luci.uvl.UVL(
|
||
|
type(options.schemedir) == "string" and options.schemedir,
|
||
|
type(options.configdir) == "string" and options.configdir
|
||
|
)
|
||
|
|
||
|
local cso = luci.util.split( arguments[2], "." )
|
||
|
local ok, err
|
||
|
|
||
|
if arguments[1] == "verify-scheme" then
|
||
|
uvl:read_scheme( 'schema', cso[1] )
|
||
|
|
||
|
local uci = uvl.uci.cursor(
|
||
|
type(options.configdir) == "string"
|
||
|
and options.configdir or uvl.schemedir .. '/default'
|
||
|
)
|
||
|
|
||
|
ok, err = uvl:validate_config( cso[1], uci:get_all(cso[1]) )
|
||
|
if err then err.code = luci.uvl.errors.ERR_SCHEME end
|
||
|
else
|
||
|
ok, err = uvl:validate( unpack(cso) )
|
||
|
end
|
||
|
|
||
|
if ok then
|
||
|
if not options.silent then
|
||
|
print( string.format(
|
||
|
'%s "%s" validates fine!',
|
||
|
( arguments[1] == "verify-scheme" and "Scheme" or
|
||
|
( #cso == 1 and "Config" or
|
||
|
( #cso == 2 and "Section" or "Option" ) ) ),
|
||
|
table.concat(cso, ".")
|
||
|
) )
|
||
|
end
|
||
|
os.exit( 0 )
|
||
|
else
|
||
|
if not options.silent then print( err and err:string() or "Unknown error" ) end
|
||
|
os.exit( 1 )
|
||
|
end
|
||
|
else
|
||
|
genspec( arguments[2] )
|
||
|
end
|