mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-12-25 15:06:47 +02:00
Integrate basic UCI config file validation support
Needs more testing and validation is not enforced yet Code contributed by Fraunhofer Fokus git-svn-id: svn://svn.openwrt.org/openwrt/trunk@6391 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
parent
ddc24aa87e
commit
79386b5db7
@ -1,8 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# Shell script for interacting with config files
|
# Shell script for interacting with config files
|
||||||
#
|
#
|
||||||
# Copyright (C) 2006 by Fokus Fraunhofer <carsten.tittel@fokus.fraunhofer.de>
|
# Copyright (C) 2006 Fokus Fraunhofer <carsten.tittel@fokus.fraunhofer.de>
|
||||||
# Copyright (C) 2006 by Felix Fietkau <nbd@openwrt.org>
|
# Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@ -18,8 +18,8 @@
|
|||||||
# along with this program; if not, write to the Free Software
|
# along with this program; if not, write to the Free Software
|
||||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
. /etc/functions.sh
|
. $UCI_ROOT/etc/functions.sh
|
||||||
include /lib/config
|
include $UCI_ROOT/lib/config
|
||||||
|
|
||||||
SEP="[^0-9A-Za-z_]"
|
SEP="[^0-9A-Za-z_]"
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ do_show() {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
for package in ${PACKAGE:-$(cd /etc/config; ls)}; do
|
for package in ${PACKAGE:-$(cd $UCI_ROOT/etc/config; ls)}; do
|
||||||
SECTION=""
|
SECTION=""
|
||||||
|
|
||||||
config_cb() {
|
config_cb() {
|
||||||
@ -136,6 +136,14 @@ do_show() {
|
|||||||
done
|
done
|
||||||
}
|
}
|
||||||
|
|
||||||
|
do_validate() {
|
||||||
|
[ "$#" -ne 1 ] && {
|
||||||
|
uci_usage validate
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
uci_validate "$1" || exit "$?"
|
||||||
|
}
|
||||||
|
|
||||||
uci_usage() {
|
uci_usage() {
|
||||||
case "$1" in
|
case "$1" in
|
||||||
show) echo "$0 show [<package>[.<config>]]";;
|
show) echo "$0 show [<package>[.<config>]]";;
|
||||||
@ -144,6 +152,7 @@ uci_usage() {
|
|||||||
del) echo "$0 del <package>.<config>[.<option>]";;
|
del) echo "$0 del <package>.<config>[.<option>]";;
|
||||||
rename) echo "$0 rename <package> <config> <name>";;
|
rename) echo "$0 rename <package> <config> <name>";;
|
||||||
commit) echo "$0 commit [<package> ... ]";;
|
commit) echo "$0 commit [<package> ... ]";;
|
||||||
|
validate) echo "$0 validate <package>";;
|
||||||
*)
|
*)
|
||||||
echo "Syntax: $0 <command> <arguments...>"
|
echo "Syntax: $0 <command> <arguments...>"
|
||||||
echo
|
echo
|
||||||
@ -153,6 +162,7 @@ uci_usage() {
|
|||||||
uci_usage del
|
uci_usage del
|
||||||
uci_usage rename
|
uci_usage rename
|
||||||
uci_usage commit
|
uci_usage commit
|
||||||
|
uci_usage validate
|
||||||
echo
|
echo
|
||||||
exit 1
|
exit 1
|
||||||
;;
|
;;
|
||||||
@ -164,7 +174,7 @@ if [ $# -eq 0 ] ; then
|
|||||||
exit 0
|
exit 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
local CMD="$1"
|
CMD="$1"
|
||||||
shift
|
shift
|
||||||
case "$CMD" in
|
case "$CMD" in
|
||||||
set) do_set "$@";;
|
set) do_set "$@";;
|
||||||
@ -173,6 +183,7 @@ case "$CMD" in
|
|||||||
get) do_get "$@";;
|
get) do_get "$@";;
|
||||||
show) do_show "$@";;
|
show) do_show "$@";;
|
||||||
commit) do_commit "$@";;
|
commit) do_commit "$@";;
|
||||||
|
validate) do_validate "$@";;
|
||||||
*) uci_usage;;
|
*) uci_usage;;
|
||||||
esac
|
esac
|
||||||
exit 0
|
exit 0
|
||||||
|
@ -9,6 +9,7 @@ N="
|
|||||||
"
|
"
|
||||||
|
|
||||||
_C=0
|
_C=0
|
||||||
|
NO_EXPORT=1
|
||||||
|
|
||||||
hotplug_dev() {
|
hotplug_dev() {
|
||||||
env -i ACTION=$1 INTERFACE=$2 /sbin/hotplug net
|
env -i ACTION=$1 INTERFACE=$2 /sbin/hotplug net
|
||||||
@ -19,7 +20,7 @@ append() {
|
|||||||
local value="$2"
|
local value="$2"
|
||||||
local sep="${3:- }"
|
local sep="${3:- }"
|
||||||
|
|
||||||
eval "export -n -- \"$var=\${$var:+\${$var}\${value:+\$sep}}\$value\""
|
eval "export ${NO_EXPORT:+-n} -- \"$var=\${$var:+\${$var}\${value:+\$sep}}\$value\""
|
||||||
}
|
}
|
||||||
|
|
||||||
reset_cb() {
|
reset_cb() {
|
||||||
@ -32,19 +33,19 @@ config () {
|
|||||||
local cfgtype="$1"
|
local cfgtype="$1"
|
||||||
local name="$2"
|
local name="$2"
|
||||||
|
|
||||||
CONFIG_NUM_SECTIONS=$(($CONFIG_NUM_SECTIONS + 1))
|
export ${NO_EXPORT:+-n} CONFIG_NUM_SECTIONS=$(($CONFIG_NUM_SECTIONS + 1))
|
||||||
name="${name:-cfg$CONFIG_NUM_SECTIONS}"
|
name="${name:-cfg$CONFIG_NUM_SECTIONS}"
|
||||||
append CONFIG_SECTIONS "$name"
|
append CONFIG_SECTIONS "$name"
|
||||||
config_cb "$cfgtype" "$name"
|
config_cb "$cfgtype" "$name"
|
||||||
CONFIG_SECTION="$name"
|
export ${NO_EXPORT:+-n} CONFIG_SECTION="$name"
|
||||||
export -n "CONFIG_${CONFIG_SECTION}_TYPE=$cfgtype"
|
export ${NO_EXPORT:+-n} "CONFIG_${CONFIG_SECTION}_TYPE=$cfgtype"
|
||||||
}
|
}
|
||||||
|
|
||||||
option () {
|
option () {
|
||||||
local varname="$1"; shift
|
local varname="$1"; shift
|
||||||
local value="$*"
|
local value="$*"
|
||||||
|
|
||||||
export -n "CONFIG_${CONFIG_SECTION}_${varname}=$value"
|
export ${NO_EXPORT:+-n} "CONFIG_${CONFIG_SECTION}_${varname}=$value"
|
||||||
option_cb "$varname" "$*"
|
option_cb "$varname" "$*"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,12 +59,12 @@ config_rename() {
|
|||||||
for oldvar in `set | grep ^CONFIG_${OLD}_ | \
|
for oldvar in `set | grep ^CONFIG_${OLD}_ | \
|
||||||
sed -e 's/\(.*\)=.*$/\1/'` ; do
|
sed -e 's/\(.*\)=.*$/\1/'` ; do
|
||||||
newvar="CONFIG_${NEW}_${oldvar##CONFIG_${OLD}_}"
|
newvar="CONFIG_${NEW}_${oldvar##CONFIG_${OLD}_}"
|
||||||
eval "export -n \"$newvar=\${$oldvar}\""
|
eval "export ${NO_EXPORT:+-n} \"$newvar=\${$oldvar}\""
|
||||||
unset "$oldvar"
|
unset "$oldvar"
|
||||||
done
|
done
|
||||||
CONFIG_SECTIONS="$(echo " $CONFIG_SECTIONS " | sed -e "s, $OLD , $NEW ,")"
|
export ${NO_EXPORT:+-n} CONFIG_SECTIONS="$(echo " $CONFIG_SECTIONS " | sed -e "s, $OLD , $NEW ,")"
|
||||||
|
|
||||||
[ "$CONFIG_SECTION" = "$OLD" ] && CONFIG_SECTION="$NEW"
|
[ "$CONFIG_SECTION" = "$OLD" ] && export ${NO_EXPORT:+-n} CONFIG_SECTION="$NEW"
|
||||||
}
|
}
|
||||||
|
|
||||||
config_unset() {
|
config_unset() {
|
||||||
@ -74,8 +75,8 @@ config_clear() {
|
|||||||
local SECTION="$1"
|
local SECTION="$1"
|
||||||
local oldvar
|
local oldvar
|
||||||
|
|
||||||
CONFIG_SECTIONS="$(echo " $CONFIG_SECTIONS " | sed -e "s, $OLD , ,")"
|
export ${NO_EXPORT:+-n} CONFIG_SECTIONS="$(echo " $CONFIG_SECTIONS " | sed -e "s, $OLD , ,")"
|
||||||
CONFIG_SECTIONS="${SECTION:+$CONFIG_SECTIONS}"
|
export ${NO_EXPORT:+-n} CONFIG_SECTIONS="${SECTION:+$CONFIG_SECTIONS}"
|
||||||
|
|
||||||
for oldvar in `set | grep ^CONFIG_${SECTION:+${SECTION}_} | \
|
for oldvar in `set | grep ^CONFIG_${SECTION:+${SECTION}_} | \
|
||||||
sed -e 's/\(.*\)=.*$/\1/'` ; do
|
sed -e 's/\(.*\)=.*$/\1/'` ; do
|
||||||
@ -84,11 +85,11 @@ config_clear() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
config_load() {
|
config_load() {
|
||||||
local file="/etc/config/$1"
|
local file="$UCI_ROOT/etc/config/$1"
|
||||||
_C=0
|
_C=0
|
||||||
CONFIG_SECTIONS=
|
export ${NO_EXPORT:+-n} CONFIG_SECTIONS=
|
||||||
CONFIG_NUM_SECTIONS=0
|
export ${NO_EXPORT:+-n} CONFIG_NUM_SECTIONS=0
|
||||||
CONFIG_SECTION=
|
export ${NO_EXPORT:+-n} CONFIG_SECTION=
|
||||||
|
|
||||||
[ -e "$file" ] && {
|
[ -e "$file" ] && {
|
||||||
. $file
|
. $file
|
||||||
@ -100,7 +101,7 @@ config_load() {
|
|||||||
config_get() {
|
config_get() {
|
||||||
case "$3" in
|
case "$3" in
|
||||||
"") eval "echo \"\${CONFIG_${1}_${2}}\"";;
|
"") eval "echo \"\${CONFIG_${1}_${2}}\"";;
|
||||||
*) eval "export -n -- \"$1=\${CONFIG_${2}_${3}}\"";;
|
*) eval "export ${NO_EXPORT:+-n} -- \"$1=\${CONFIG_${2}_${3}}\"";;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +109,7 @@ config_set() {
|
|||||||
local section="$1"
|
local section="$1"
|
||||||
local option="$2"
|
local option="$2"
|
||||||
local value="$3"
|
local value="$3"
|
||||||
export -n "CONFIG_${section}_${option}=$value"
|
export ${NO_EXPORT:+-n} "CONFIG_${section}_${option}=$value"
|
||||||
}
|
}
|
||||||
|
|
||||||
config_foreach() {
|
config_foreach() {
|
||||||
@ -155,12 +156,12 @@ strtok() { # <string> { <variable> [<separator>] ... }
|
|||||||
|
|
||||||
val="${val#$tmp$2}"
|
val="${val#$tmp$2}"
|
||||||
|
|
||||||
export -n "$1=$tmp"; count=$((count+1))
|
export ${NO_EXPORT:+-n} "$1=$tmp"; count=$((count+1))
|
||||||
shift 2
|
shift 2
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ $# -gt 0 -a "$val" ]; then
|
if [ $# -gt 0 -a "$val" ]; then
|
||||||
export -n "$1=$val"; count=$((count+1))
|
export ${NO_EXPORT:+-n} "$1=$val"; count=$((count+1))
|
||||||
fi
|
fi
|
||||||
|
|
||||||
return $count
|
return $count
|
||||||
|
255
package/base-files/files/lib/config/parse_spec.awk
Normal file
255
package/base-files/files/lib/config/parse_spec.awk
Normal file
@ -0,0 +1,255 @@
|
|||||||
|
# AWK file for parsing uci specification files
|
||||||
|
#
|
||||||
|
# Copyright (C) 2006 by Fokus Fraunhofer <carsten.tittel@fokus.fraunhofer.de>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# general: unfortunately, the development was done using gawk providing
|
||||||
|
# a different match() functions than e.g. mawk on debian systems
|
||||||
|
# - therefore, the script was changed to run on most awk's
|
||||||
|
# - even things like [:space:] are not used
|
||||||
|
#
|
||||||
|
# - script parses the config section definition contained in one
|
||||||
|
# specification file
|
||||||
|
# global variables:
|
||||||
|
# * section - contains the current config section name
|
||||||
|
# * var - contains the name of the current config option
|
||||||
|
# * type - contains the type of the current config option
|
||||||
|
# * required - contains the requirements of the current config option
|
||||||
|
# * optional - contains the optional scope of the current config option
|
||||||
|
# * vars[] - array, contains the name of all config options valid within
|
||||||
|
# a certain config section, format: csv
|
||||||
|
#
|
||||||
|
# XXX todo: more than one config option with the same in different section
|
||||||
|
# will clash for the following tables
|
||||||
|
# * types[] - contains the type of a config option
|
||||||
|
# * reqs[] - contains the requirements of a config option
|
||||||
|
# * opts[] - contains the optional scope of a config option
|
||||||
|
#
|
||||||
|
BEGIN {
|
||||||
|
section_count=1
|
||||||
|
section = ""
|
||||||
|
simple_types = "int|ip|netmask|string|wep|hostname|mac|port|ports|wpapsk"
|
||||||
|
}
|
||||||
|
|
||||||
|
# function print_specification
|
||||||
|
# - prints all information about the created tables containing the
|
||||||
|
# specification
|
||||||
|
function print_specification() {
|
||||||
|
for (section in vars) {
|
||||||
|
printf("%s\n",section);
|
||||||
|
split(vars[section],arr,",")
|
||||||
|
for (idx in arr) {
|
||||||
|
printf("\t%s[%s]",arr[idx],types[section "_" arr[idx]]);
|
||||||
|
if (length(reqs[section "_" arr[idx]])) {
|
||||||
|
if (reqs[section "_" arr[idx]]==1) {
|
||||||
|
printf(",req");
|
||||||
|
}else{
|
||||||
|
printf(", req(%s)", reqs[section "_" arr[idx]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (length(opts[section "_" arr[idx]])) {
|
||||||
|
printf(", opt(%s)", opts[section "_" arr[idx]]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function reset_option() {
|
||||||
|
# just set global variables parsed on one line back to defaults
|
||||||
|
var = ""
|
||||||
|
type = ""
|
||||||
|
required = ""
|
||||||
|
optional = ""
|
||||||
|
found = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
function store_option() {
|
||||||
|
# save all information about a config option parsed from the spec file
|
||||||
|
# to the relevant tables for future use
|
||||||
|
|
||||||
|
# first check minimum requirements for storing information
|
||||||
|
if (!length(section)) {
|
||||||
|
print STDERR "line " NR ": section definition missing"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if (!length(var)) {
|
||||||
|
print STDERR "line " NR ": invalid config option name"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
if (!length(type)) {
|
||||||
|
print STDERR "line " NR ": invalid config option type"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# add config options to the names of options available for this
|
||||||
|
# section
|
||||||
|
if (exists[section]!=1) {
|
||||||
|
section_names[section_count] = section
|
||||||
|
section_count++
|
||||||
|
exists[section] = 1
|
||||||
|
vars[section] = var
|
||||||
|
} else {
|
||||||
|
vars[section] = vars[section] "," var
|
||||||
|
}
|
||||||
|
|
||||||
|
# save the type, the requirements and the optional scope of the
|
||||||
|
# config option
|
||||||
|
types[section "_" var] = type
|
||||||
|
reqs[section "_" var] = required
|
||||||
|
opts[section "_" var] = optional
|
||||||
|
}
|
||||||
|
|
||||||
|
/^declare -x|^export/ {
|
||||||
|
sub(/^declare -x /,"")
|
||||||
|
sub(/^export /,"")
|
||||||
|
split($0,arr,"=")
|
||||||
|
val=substr(arr[2],2,length(arr[2])-2)
|
||||||
|
ENVIRON[arr[1]] = val
|
||||||
|
next
|
||||||
|
}
|
||||||
|
|
||||||
|
# main parsing function
|
||||||
|
# this is done in one function block to allow multiple semicolon separated
|
||||||
|
# definitions on one line
|
||||||
|
{
|
||||||
|
# replace leading/trailing white space
|
||||||
|
gsub("^[ \t\n]+","");
|
||||||
|
gsub("[ \t\n]+$","");
|
||||||
|
|
||||||
|
# comments are removed
|
||||||
|
# XXX todo: check for quoted comments??
|
||||||
|
if (match($0,/[^#]*/)) {
|
||||||
|
rest=substr($0,RSTART,RLENGTH)
|
||||||
|
} else {
|
||||||
|
rest=$0
|
||||||
|
}
|
||||||
|
|
||||||
|
# match the config section "<section> {"
|
||||||
|
if (match(rest,/^[^ \t\n{]+[ \t\n]*\{/)) {
|
||||||
|
match(rest,/^[^ \t\n{]+/)
|
||||||
|
section = substr(rest,RSTART,RLENGTH)
|
||||||
|
rest=substr($0,RSTART+RLENGTH);
|
||||||
|
match(rest,/[ \t\n]*\{/)
|
||||||
|
rest=substr(rest,RSTART+RLENGTH)
|
||||||
|
# check for array indication
|
||||||
|
if (match(section,/\[[ \t\n]*\]/)) {
|
||||||
|
section=substr(section,1,RSTART-1)
|
||||||
|
multiple[section] = 1
|
||||||
|
} else {
|
||||||
|
multiple[section] = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_option()
|
||||||
|
|
||||||
|
# parse the remaing line as long as there is something to parse
|
||||||
|
while (rest ~ "[^ \t\n}]+") {
|
||||||
|
found = 0
|
||||||
|
|
||||||
|
# get option name and option type
|
||||||
|
# first, check for "simple" datatype definitions
|
||||||
|
if (match(rest,"[^: \t\n]+[ \t\n]*:[ \t\n]*(" \
|
||||||
|
simple_types ")")){
|
||||||
|
match(rest,"[^: \t\n]+")
|
||||||
|
var=substr(rest,RSTART,RLENGTH)
|
||||||
|
rest=substr(rest,RSTART+RLENGTH)
|
||||||
|
match(rest,"[ \t\n]*:[ \t\n]*")
|
||||||
|
rest=substr(rest,RSTART+RLENGTH)
|
||||||
|
match(rest,"(" simple_types ")")
|
||||||
|
type=substr(rest,RSTART,RLENGTH)
|
||||||
|
rest = substr(rest,RSTART+RLENGTH)
|
||||||
|
found = 1
|
||||||
|
# next, check for enum definitions
|
||||||
|
} else if (match(rest,/[^: \t\n]+[ \t\n]*:[ \t\n]*enum\([^\)]+\)/ )) {
|
||||||
|
match(rest,"[^: \t\n]+")
|
||||||
|
var=substr(rest,RSTART,RLENGTH)
|
||||||
|
rest=substr(rest,RSTART+RLENGTH)
|
||||||
|
match(rest,/[ \t\n]*:[ \t\n]*enum\(/)
|
||||||
|
rest=substr(rest,RSTART+RLENGTH)
|
||||||
|
match(rest,/[^\)]+/)
|
||||||
|
type="enum," substr(rest,RSTART,RLENGTH)
|
||||||
|
rest = substr(rest,RSTART+RLENGTH+1)
|
||||||
|
found=1
|
||||||
|
}
|
||||||
|
|
||||||
|
# after the name and the type,
|
||||||
|
# get the option requirements/scope
|
||||||
|
if (match(rest,/[^,]*,[ \t\n]*required\[[^]]+\]/)) {
|
||||||
|
match(rest,"[^,]*")
|
||||||
|
save=substr(rest,RSTART,RLENGTH)
|
||||||
|
rest=substr(rest,RSTART+RLENGTH)
|
||||||
|
match(rest,/,[ \t\n]*required\[/);
|
||||||
|
rest=substr(rest,RSTART+RLENGTH)
|
||||||
|
match(rest,/[^]]+\]/)
|
||||||
|
required=substr(rest,RSTART,RLENGTH-1)
|
||||||
|
save=save substr(rest,RSTART+RLENGTH)
|
||||||
|
rest=save
|
||||||
|
found=1
|
||||||
|
} else if (match(rest,/[^,]*,[ \t\n]*required/)) {
|
||||||
|
match(rest,"[^,]*")
|
||||||
|
save=substr(rest,RSTART,RLENGTH)
|
||||||
|
rest=substr(rest,RSTART+RLENGTH)
|
||||||
|
match(rest,",[ \t\n]*required");
|
||||||
|
rest=substr(rest,RSTART+RLENGTH)
|
||||||
|
required=1
|
||||||
|
save=save substr(rest,RSTART+RLENGTH)
|
||||||
|
rest=save
|
||||||
|
found=1
|
||||||
|
}
|
||||||
|
if (match(rest,/[^,]*,[ \t\n]*optional\[[^]]+\]/)) {
|
||||||
|
match(rest,"[^,]*")
|
||||||
|
save=substr(rest,RSTART,RLENGTH)
|
||||||
|
rest=substr(rest,RSTART+RLENGTH)
|
||||||
|
match(rest,/,[ \t\n]*optional\[/);
|
||||||
|
rest=substr(rest,RSTART+RLENGTH)
|
||||||
|
match(rest,/[^]]+\]/)
|
||||||
|
optional=substr(rest,RSTART,RLENGTH-1)
|
||||||
|
save=save substr(rest,RSTART+RLENGTH)
|
||||||
|
rest=save
|
||||||
|
found=1
|
||||||
|
}
|
||||||
|
|
||||||
|
# if the remaining line contains a semicolon, complete the
|
||||||
|
# specification of the config options
|
||||||
|
if (match(rest, "^[ \t\n]*;(.*)")) {
|
||||||
|
match(rest,"^[ \t\n]*;")
|
||||||
|
rest=substr(rest,RSTART+RLENGTH)
|
||||||
|
if (found==1) {
|
||||||
|
store_option()
|
||||||
|
}
|
||||||
|
reset_option()
|
||||||
|
|
||||||
|
# if nothing matched on this line, clear the rest
|
||||||
|
} else if (!found) {
|
||||||
|
rest = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# after the line is pared, store the configuration option in the
|
||||||
|
# table if any has been defined
|
||||||
|
if (length(var)) {
|
||||||
|
store_option()
|
||||||
|
reset_option()
|
||||||
|
}
|
||||||
|
# close the section if the line contained a closing section bracket,
|
||||||
|
# XXX todo: check if this has to be done more intelligent
|
||||||
|
if ($0 ~ /\}/) {
|
||||||
|
section=""
|
||||||
|
}
|
||||||
|
}
|
7
package/base-files/files/lib/config/specs/network.spec
Normal file
7
package/base-files/files/lib/config/specs/network.spec
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
interface[] {
|
||||||
|
proto: string, required;
|
||||||
|
ipaddr: ip, required[proto=static];
|
||||||
|
netmask: ip, required[proto=static];
|
||||||
|
gateway: ip;
|
||||||
|
dns: ip;
|
||||||
|
}
|
15
package/base-files/files/lib/config/uci.sh
Executable file → Normal file
15
package/base-files/files/lib/config/uci.sh
Executable file → Normal file
@ -1,8 +1,8 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# Shell script defining macros for manipulating config files
|
# Shell script defining macros for manipulating config files
|
||||||
#
|
#
|
||||||
# Copyright (C) 2006 by Fokus Fraunhofer <carsten.tittel@fokus.fraunhofer.de>
|
# Copyright (C) 2006 Fokus Fraunhofer <carsten.tittel@fokus.fraunhofer.de>
|
||||||
# Copyright (C) 2006 by Felix Fietkau <nbd@openwrt.org>
|
# Copyright (C) 2006,2007 Felix Fietkau <nbd@openwrt.org>
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it and/or modify
|
# This program is free software; you can redistribute it and/or modify
|
||||||
# it under the terms of the GNU General Public License as published by
|
# it under the terms of the GNU General Public License as published by
|
||||||
@ -31,7 +31,7 @@ uci_load() {
|
|||||||
uci_do_update() {
|
uci_do_update() {
|
||||||
local FILENAME="$1"
|
local FILENAME="$1"
|
||||||
local UPDATE="$2"
|
local UPDATE="$2"
|
||||||
awk -f /lib/config/uci-update.awk -f - <<EOF
|
awk -f $UCI_ROOT/lib/config/uci-update.awk -f - <<EOF
|
||||||
BEGIN {
|
BEGIN {
|
||||||
config = read_file("$FILENAME")
|
config = read_file("$FILENAME")
|
||||||
$UPDATE
|
$UPDATE
|
||||||
@ -94,9 +94,10 @@ uci_remove() {
|
|||||||
uci_commit() {
|
uci_commit() {
|
||||||
local PACKAGE="$1"
|
local PACKAGE="$1"
|
||||||
local PACKAGE_BASE="$(basename "$PACKAGE")"
|
local PACKAGE_BASE="$(basename "$PACKAGE")"
|
||||||
|
|
||||||
mkdir -p /tmp/.uci
|
mkdir -p /tmp/.uci
|
||||||
lock "/tmp/.uci/$PACKAGE_BASE.lock"
|
LOCK=`which lock` || LOCK=:
|
||||||
|
$LOCK "/tmp/.uci/$PACKAGE_BASE.lock"
|
||||||
[ -f "/tmp/.uci/$PACKAGE_BASE" ] && (
|
[ -f "/tmp/.uci/$PACKAGE_BASE" ] && (
|
||||||
updatestr=""
|
updatestr=""
|
||||||
|
|
||||||
@ -128,13 +129,13 @@ uci_commit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
config_load "$PACKAGE"
|
config_load "$PACKAGE"
|
||||||
CONFIG_FILENAME="${CONFIG_FILENAME:-$ROOT/etc/config/$PACKAGE_BASE}"
|
CONFIG_FILENAME="${CONFIG_FILENAME:-$UCI_ROOT/etc/config/$PACKAGE_BASE}"
|
||||||
uci_do_update "$CONFIG_FILENAME" "$updatestr" > "/tmp/.uci/$PACKAGE_BASE.new" && {
|
uci_do_update "$CONFIG_FILENAME" "$updatestr" > "/tmp/.uci/$PACKAGE_BASE.new" && {
|
||||||
mv -f "/tmp/.uci/$PACKAGE_BASE.new" "$CONFIG_FILENAME" && \
|
mv -f "/tmp/.uci/$PACKAGE_BASE.new" "$CONFIG_FILENAME" && \
|
||||||
rm -f "/tmp/.uci/$PACKAGE_BASE"
|
rm -f "/tmp/.uci/$PACKAGE_BASE"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
lock -u "/tmp/.uci/$PACKAGE_BASE.lock"
|
$LOCK -u "/tmp/.uci/$PACKAGE_BASE.lock"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
74
package/base-files/files/lib/config/validate.sh
Normal file
74
package/base-files/files/lib/config/validate.sh
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
# Shell script defining validating configuration macros
|
||||||
|
#
|
||||||
|
# Copyright (C) 2006 by Fokus Fraunhofer <carsten.tittel@fokus.fraunhofer.de>
|
||||||
|
# Copyright (C) 2007 by Felix Fietkau <nbd@openwrt.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
|
||||||
|
|
||||||
|
validate_spec() {
|
||||||
|
export | grep 'CONFIG_' | cat - "$@" | awk \
|
||||||
|
-f $UCI_ROOT/lib/config/validate_config.awk \
|
||||||
|
-f $UCI_ROOT/lib/config/parse_spec.awk \
|
||||||
|
-f $UCI_ROOT/lib/config/validate_spec.awk
|
||||||
|
}
|
||||||
|
|
||||||
|
validate_config_cb () {
|
||||||
|
local TYPE
|
||||||
|
local res=
|
||||||
|
|
||||||
|
[ -n "${CONFIG_SECTION}" ] || return 0
|
||||||
|
|
||||||
|
config_get TYPE ${CONFIG_SECTION} TYPE
|
||||||
|
[ -n "$TYPE" ] || return 0
|
||||||
|
|
||||||
|
if type validate_${PACKAGE}_${TYPE} >/dev/null 2>&1; then
|
||||||
|
validate_${PACKAGE}_${TYPE}
|
||||||
|
res="$?"
|
||||||
|
else
|
||||||
|
if [ -f $UCI_ROOT/lib/config/specs/${PACKAGE}.spec ]; then
|
||||||
|
# no special defined, use default one
|
||||||
|
validate_spec $UCI_ROOT/lib/config/specs/${PACKAGE}.spec
|
||||||
|
res="$?"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
VALIDATE_RES="${VALIDATE_RES:-$res}"
|
||||||
|
}
|
||||||
|
|
||||||
|
uci_validate() {(
|
||||||
|
PACKAGE="$1"
|
||||||
|
FILE="$2"
|
||||||
|
VALIDATE_RES=
|
||||||
|
|
||||||
|
[ -z "${PACKAGE}" ] && {
|
||||||
|
echo "Error: no package defined"
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
reset_cb
|
||||||
|
config_cb() {
|
||||||
|
validate_config_cb "$@"
|
||||||
|
}
|
||||||
|
unset NO_EXPORT
|
||||||
|
if [ -n "$FILE" ]; then
|
||||||
|
. "$FILE"
|
||||||
|
config
|
||||||
|
else
|
||||||
|
config_load "$1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
return ${VALIDATE_RES:-0}
|
||||||
|
)}
|
105
package/base-files/files/lib/config/validate_config.awk
Normal file
105
package/base-files/files/lib/config/validate_config.awk
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
# AWK file for validating uci specification files
|
||||||
|
#
|
||||||
|
# Copyright (C) 2006 by Fokus Fraunhofer <carsten.tittel@fokus.fraunhofer.de>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
function is_int(value) {
|
||||||
|
valid = 1
|
||||||
|
if (value !~ /^[0-9]*$/) { valid = 0 }
|
||||||
|
return valid
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_netmask(value) {
|
||||||
|
return is_ip(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_ip(value) {
|
||||||
|
valid = 1
|
||||||
|
if ((value != "") && (value !~ /^[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$/)) valid = 0
|
||||||
|
else {
|
||||||
|
split(value, ipaddr, "\\.")
|
||||||
|
for (i = 1; i <= 4; i++) {
|
||||||
|
if ((ipaddr[i] < 0) || (ipaddr[i] > 255)) valid = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valid
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_wep(value) {
|
||||||
|
valid = 1
|
||||||
|
if (value !~ /^[0-9A-Fa-f]*$/) {
|
||||||
|
valid = 0
|
||||||
|
} else if ((length(value) != 0) && (length(value) != 10) && (length(value) != 26)) {
|
||||||
|
valid = 0
|
||||||
|
} else if (value ~ /0$/) {
|
||||||
|
valid = 0
|
||||||
|
}
|
||||||
|
return valid
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_hostname(value) {
|
||||||
|
valid = 1
|
||||||
|
if (value !~ /^[0-9a-zA-z\.\-]*$/) {
|
||||||
|
valid = 0
|
||||||
|
}
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_string(value) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_mac(value) {
|
||||||
|
valid = 1
|
||||||
|
if ((value != "") && (value !~ /^[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]:[0-9a-fA-F][0-9a-fA-F]$/)) {
|
||||||
|
valid = 0
|
||||||
|
}
|
||||||
|
return valid
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_port(value) {
|
||||||
|
valid = 1
|
||||||
|
if (value !~ /^[0-9]*$/) {
|
||||||
|
valid = 0
|
||||||
|
}
|
||||||
|
return valid
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_ports(value) {
|
||||||
|
valid = 1
|
||||||
|
n = split(value ",", ports, ",")
|
||||||
|
for (i = 1; i <= n; i++) {
|
||||||
|
if ((ports[i] !~ /^[0-9]*$/) && (ports[i] !~ /^[0-9][0-9]*-[0-9][0-9]*$/)) {
|
||||||
|
valid = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return valid
|
||||||
|
}
|
||||||
|
|
||||||
|
function is_wpapsk(value) {
|
||||||
|
valid = 1
|
||||||
|
if (length(value) > 64) {
|
||||||
|
valid = 0
|
||||||
|
}
|
||||||
|
if ((length(value) != 0) && (length(value) < 8)) {
|
||||||
|
valid = 0
|
||||||
|
}
|
||||||
|
if ((length(value) == 64) && (value ~ /[^0-9a-fA-F]/)) {
|
||||||
|
valid = 0
|
||||||
|
}
|
||||||
|
return valid
|
||||||
|
}
|
||||||
|
|
171
package/base-files/files/lib/config/validate_spec.awk
Normal file
171
package/base-files/files/lib/config/validate_spec.awk
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
# AWK file for validating uci specification files
|
||||||
|
#
|
||||||
|
# Copyright (C) 2006 by Fokus Fraunhofer <carsten.tittel@fokus.fraunhofer.de>
|
||||||
|
# Copyright (C) 2007 by Felix Fietkau <nbd@openwrt.org>
|
||||||
|
#
|
||||||
|
# This program is free software; you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU General Public License as published by
|
||||||
|
# the Free Software Foundation; either version 2 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
# General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU General Public License
|
||||||
|
# along with this program; if not, write to the Free Software
|
||||||
|
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# general: unfortunately, the development was done using gawk providing
|
||||||
|
# a different match() functions than e.g. mawk on debian systems
|
||||||
|
# - therefore, the script was changed to run on most awk's
|
||||||
|
# - even things like [:space:] are not used
|
||||||
|
#
|
||||||
|
# - script parses the config section definition contained in one
|
||||||
|
# specification file
|
||||||
|
# global variables:
|
||||||
|
# * section - contains the current config section name
|
||||||
|
# * var - contains the name of the current config option
|
||||||
|
# * type - contains the type of the current config option
|
||||||
|
# * required - contains the requirements of the current config option
|
||||||
|
# * optional - contains the optional scope of the current config option
|
||||||
|
# * vars[] - array, contains the name of all config options valid within
|
||||||
|
# a certain config section, format: csv
|
||||||
|
#
|
||||||
|
# XXX todo: more than one config option with the same in different section
|
||||||
|
# will clash for the following tables
|
||||||
|
# * types[] - contains the type of a config option
|
||||||
|
# * reqs[] - contains the requirements of a config option
|
||||||
|
# * opts[] - contains the optional scope of a config option
|
||||||
|
#
|
||||||
|
|
||||||
|
# - check requirement validates, if the config option is required in
|
||||||
|
# the config section type and if so, if it is defined
|
||||||
|
# - the functions exits with error in case of non-conforming
|
||||||
|
# behaviour
|
||||||
|
# XXX todo: use return instead of exit
|
||||||
|
#
|
||||||
|
function check_requirements(vsec,var) {
|
||||||
|
# check, if config option is required in all cases
|
||||||
|
if (reqs[vsec "_" var] == 1) {
|
||||||
|
# option is always required, is it defined?
|
||||||
|
if (!length(ENVIRON["CONFIG_" vsec "_" var])) {
|
||||||
|
print STDERR "Error: missing config option " var " in " vsec
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# check, if config option is required only when other options
|
||||||
|
# have certain values
|
||||||
|
} else if (length(reqs[vsec "_" var])) {
|
||||||
|
# - check all requirements, e.g. proto=static,proto=pptp
|
||||||
|
# - note, that the required flag is tiggered if at least one
|
||||||
|
# of the conditions is met
|
||||||
|
split(reqs[vsec "_" var],arr,",");
|
||||||
|
for (idx in arr) {
|
||||||
|
# parse the condition space tolerant
|
||||||
|
if (!match(arr[idx],"^[ \t\n]*[^ \t\n=]+"\
|
||||||
|
"[ \t\n]*=.+")) {
|
||||||
|
print STDERR "Error: invalid requirement "\
|
||||||
|
"in spec file for " var " : " arr[idx]
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
# get the name of the variable
|
||||||
|
match(arr[idx],"[^ \t\n=]+");
|
||||||
|
name=substr(arr[idx],RSTART,RLENGTH)
|
||||||
|
mrest=substr(arr[idx],RSTART+RLENGTH)
|
||||||
|
# get the spaces
|
||||||
|
match(mrest,"[ \t\n]*=[ \t\n]*")
|
||||||
|
val=substr(mrest,RSTART+RLENGTH)
|
||||||
|
# check the condition
|
||||||
|
if (ENVIRON["CONFIG_" vsec "_" name] == val) {
|
||||||
|
# condition is met, check requirement
|
||||||
|
if (!length(ENVIRON["CONFIG_" vsec "_" var])) {
|
||||||
|
print STDERR "Error: missing config " \
|
||||||
|
"option " var " in " vsec
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# is_valid just returns true(1)/false(0) if the
|
||||||
|
# given value is conform with the type definition
|
||||||
|
# NOTE: this function needs the type validating function from
|
||||||
|
# validate_config.awk
|
||||||
|
#
|
||||||
|
function is_valid(type,value) {
|
||||||
|
|
||||||
|
# the enum type contains a definition of all allowed values as csv
|
||||||
|
# e.g. enum,alpha,beta,gamma
|
||||||
|
if (type ~ "enum" ) {
|
||||||
|
split(type,tarr,",")
|
||||||
|
for (num in tarr) {
|
||||||
|
if (num > 0) {
|
||||||
|
gsub("^[ \t\n]*","",tarr[num]);
|
||||||
|
gsub("[ \t\n]*$","",tarr[num]);
|
||||||
|
if (tarr[num] == value) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
# all other types are checked as defined in the former validate.awk
|
||||||
|
if (type ~ "int") return is_int(value)
|
||||||
|
if (type ~ "ip" ) return is_ip(value)
|
||||||
|
if (type ~ "netmask" ) return is_netmask(value)
|
||||||
|
if (type ~ "string" ) return is_string(value)
|
||||||
|
if (type ~ "wep" ) return is_wep(value)
|
||||||
|
if (type ~ "hostname" ) return is_hostname(value)
|
||||||
|
if (type ~ "mac" ) return is_mac(value)
|
||||||
|
if (type ~ "port" ) return is_port(value)
|
||||||
|
if (type ~ "ports" ) return is_ports(value)
|
||||||
|
if (type ~ "wpapsk" ) return is_wpapsk(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
# validate_config compares the specification as parsed from the spec file
|
||||||
|
# with the environment variables
|
||||||
|
# CONFIG_SECTION contains the relevant config section name, e.g. wan
|
||||||
|
# CONFIG_<section>_TYPE contains the type of the config, e.g. interface
|
||||||
|
# CONFIG_<section>_<var> contains the value of the config option <var>
|
||||||
|
#
|
||||||
|
function validate_config() {
|
||||||
|
# get the config section name
|
||||||
|
vname=ENVIRON["CONFIG_SECTION"]
|
||||||
|
if (!length(vname)) {
|
||||||
|
print STDERR "Error: no current configuration"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
# get the config section type
|
||||||
|
vsec=ENVIRON["CONFIG_" vname "_TYPE"]
|
||||||
|
if (!length(vsec)) {
|
||||||
|
print STDERR "Error: section " vsec " not found"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# loop through all config options specified for this section type
|
||||||
|
split(vars[vsec],options,",")
|
||||||
|
for (oidx in options) {
|
||||||
|
# first, look for all required attributes
|
||||||
|
var=options[oidx]
|
||||||
|
check_requirements(vname,var)
|
||||||
|
|
||||||
|
# next look at each option and validate it
|
||||||
|
val=ENVIRON["CONFIG_" vname "_" var]
|
||||||
|
if (length(val)) {
|
||||||
|
if (!is_valid(types[vsec "_" var],val)) {
|
||||||
|
print "Error: type validation error for '" var "' in section '" vname "'"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
END {
|
||||||
|
validate_config()
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user