aboutsummaryrefslogtreecommitdiffstats
path: root/package/base-files/files/lib/config/validate_spec.awk
blob: 0816c08290ef5ae462230d9fbb2365b05f6e3cbf (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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()
}