Integrate basic UCI config file validation support Needs more testing and validation...
[openwrt/openwrt.git] / package / base-files / files / lib / config / validate_spec.awk
1 # AWK file for validating uci specification files
2 #
3 # Copyright (C) 2006 by Fokus Fraunhofer <carsten.tittel@fokus.fraunhofer.de>
4 # Copyright (C) 2007 by Felix Fietkau <nbd@openwrt.org>
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #
20 #
21 # general: unfortunately, the development was done using gawk providing
22 # a different match() functions than e.g. mawk on debian systems
23 # - therefore, the script was changed to run on most awk's
24 # - even things like [:space:] are not used
25 #
26 # - script parses the config section definition contained in one
27 # specification file
28 # global variables:
29 # * section - contains the current config section name
30 # * var - contains the name of the current config option
31 # * type - contains the type of the current config option
32 # * required - contains the requirements of the current config option
33 # * optional - contains the optional scope of the current config option
34 # * vars[] - array, contains the name of all config options valid within
35 # a certain config section, format: csv
36 #
37 # XXX todo: more than one config option with the same in different section
38 # will clash for the following tables
39 # * types[] - contains the type of a config option
40 # * reqs[] - contains the requirements of a config option
41 # * opts[] - contains the optional scope of a config option
42 #
43
44 # - check requirement validates, if the config option is required in
45 # the config section type and if so, if it is defined
46 # - the functions exits with error in case of non-conforming
47 # behaviour
48 # XXX todo: use return instead of exit
49 #
50 function check_requirements(vsec,var) {
51 # check, if config option is required in all cases
52 if (reqs[vsec "_" var] == 1) {
53 # option is always required, is it defined?
54 if (!length(ENVIRON["CONFIG_" vsec "_" var])) {
55 print STDERR "Error: missing config option " var " in " vsec
56 exit 1
57 }
58
59 # check, if config option is required only when other options
60 # have certain values
61 } else if (length(reqs[vsec "_" var])) {
62 # - check all requirements, e.g. proto=static,proto=pptp
63 # - note, that the required flag is tiggered if at least one
64 # of the conditions is met
65 split(reqs[vsec "_" var],arr,",");
66 for (idx in arr) {
67 # parse the condition space tolerant
68 if (!match(arr[idx],"^[ \t\n]*[^ \t\n=]+"\
69 "[ \t\n]*=.+")) {
70 print STDERR "Error: invalid requirement "\
71 "in spec file for " var " : " arr[idx]
72 exit 1
73 }
74 # get the name of the variable
75 match(arr[idx],"[^ \t\n=]+");
76 name=substr(arr[idx],RSTART,RLENGTH)
77 mrest=substr(arr[idx],RSTART+RLENGTH)
78 # get the spaces
79 match(mrest,"[ \t\n]*=[ \t\n]*")
80 val=substr(mrest,RSTART+RLENGTH)
81 # check the condition
82 if (ENVIRON["CONFIG_" vsec "_" name] == val) {
83 # condition is met, check requirement
84 if (!length(ENVIRON["CONFIG_" vsec "_" var])) {
85 print STDERR "Error: missing config " \
86 "option " var " in " vsec
87 exit 1
88 }
89 }
90 }
91 }
92 }
93
94 # is_valid just returns true(1)/false(0) if the
95 # given value is conform with the type definition
96 # NOTE: this function needs the type validating function from
97 # validate_config.awk
98 #
99 function is_valid(type,value) {
100
101 # the enum type contains a definition of all allowed values as csv
102 # e.g. enum,alpha,beta,gamma
103 if (type ~ "enum" ) {
104 split(type,tarr,",")
105 for (num in tarr) {
106 if (num > 0) {
107 gsub("^[ \t\n]*","",tarr[num]);
108 gsub("[ \t\n]*$","",tarr[num]);
109 if (tarr[num] == value) {
110 return 1
111 }
112 }
113 }
114 return 0;
115 }
116
117 # all other types are checked as defined in the former validate.awk
118 if (type ~ "int") return is_int(value)
119 if (type ~ "ip" ) return is_ip(value)
120 if (type ~ "netmask" ) return is_netmask(value)
121 if (type ~ "string" ) return is_string(value)
122 if (type ~ "wep" ) return is_wep(value)
123 if (type ~ "hostname" ) return is_hostname(value)
124 if (type ~ "mac" ) return is_mac(value)
125 if (type ~ "port" ) return is_port(value)
126 if (type ~ "ports" ) return is_ports(value)
127 if (type ~ "wpapsk" ) return is_wpapsk(value)
128 }
129
130 # validate_config compares the specification as parsed from the spec file
131 # with the environment variables
132 # CONFIG_SECTION contains the relevant config section name, e.g. wan
133 # CONFIG_<section>_TYPE contains the type of the config, e.g. interface
134 # CONFIG_<section>_<var> contains the value of the config option <var>
135 #
136 function validate_config() {
137 # get the config section name
138 vname=ENVIRON["CONFIG_SECTION"]
139 if (!length(vname)) {
140 print STDERR "Error: no current configuration"
141 exit 1
142 }
143 # get the config section type
144 vsec=ENVIRON["CONFIG_" vname "_TYPE"]
145 if (!length(vsec)) {
146 print STDERR "Error: section " vsec " not found"
147 exit 1
148 }
149
150 # loop through all config options specified for this section type
151 split(vars[vsec],options,",")
152 for (oidx in options) {
153 # first, look for all required attributes
154 var=options[oidx]
155 check_requirements(vname,var)
156
157 # next look at each option and validate it
158 val=ENVIRON["CONFIG_" vname "_" var]
159 if (length(val)) {
160 if (!is_valid(types[vsec "_" var],val)) {
161 print "Error: type validation error for '" var "' in section '" vname "'"
162 exit 1
163 }
164 }
165 }
166 }
167
168
169 END {
170 validate_config()
171 }