From 9405a2a6be701ee92ad0ffbe15d069bdae2cf850 Mon Sep 17 00:00:00 2001
From: Felix Fietkau <nbd@openwrt.org>
Date: Mon, 26 Feb 2007 20:04:04 +0000
Subject: Integrate basic UCI config file validation support Needs more testing
 and validation is not enforced yet

Code contributed by Fraunhofer Fokus

SVN-Revision: 6391
---
 .../base-files/files/lib/config/validate_spec.awk  | 171 +++++++++++++++++++++
 1 file changed, 171 insertions(+)
 create mode 100644 package/base-files/files/lib/config/validate_spec.awk

(limited to 'package/base-files/files/lib/config/validate_spec.awk')

diff --git a/package/base-files/files/lib/config/validate_spec.awk b/package/base-files/files/lib/config/validate_spec.awk
new file mode 100644
index 0000000..0816c08
--- /dev/null
+++ b/package/base-files/files/lib/config/validate_spec.awk
@@ -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()
+}
-- 
cgit v1.1