validate_spec.awk 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. # AWK file for validating uci specification files
  2. #
  3. # Copyright (C) 2006 by Fokus Fraunhofer <[email protected]>
  4. # Copyright (C) 2007 by Felix Fietkau <[email protected]>
  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. # - check requirement validates, if the config option is required in
  44. # the config section type and if so, if it is defined
  45. # - the functions exits with error in case of non-conforming
  46. # behaviour
  47. # XXX todo: use return instead of exit
  48. #
  49. function check_requirements(vsec,var) {
  50. # check, if config option is required in all cases
  51. if (reqs[vsec "_" var] == 1) {
  52. # option is always required, is it defined?
  53. if (!length(ENVIRON["CONFIG_" vsec "_" var])) {
  54. print STDERR "Error: missing config option " var " in " vsec
  55. exit 1
  56. }
  57. # check, if config option is required only when other options
  58. # have certain values
  59. } else if (length(reqs[vsec "_" var])) {
  60. # - check all requirements, e.g. proto=static,proto=pptp
  61. # - note, that the required flag is tiggered if at least one
  62. # of the conditions is met
  63. split(reqs[vsec "_" var],arr,",");
  64. for (idx in arr) {
  65. # parse the condition space tolerant
  66. if (!match(arr[idx],"^[ \t\n]*[^ \t\n=]+"\
  67. "[ \t\n]*=.+")) {
  68. print STDERR "Error: invalid requirement "\
  69. "in spec file for " var " : " arr[idx]
  70. exit 1
  71. }
  72. # get the name of the variable
  73. match(arr[idx],"[^ \t\n=]+");
  74. name=substr(arr[idx],RSTART,RLENGTH)
  75. mrest=substr(arr[idx],RSTART+RLENGTH)
  76. # get the spaces
  77. match(mrest,"[ \t\n]*=[ \t\n]*")
  78. val=substr(mrest,RSTART+RLENGTH)
  79. # check the condition
  80. if (ENVIRON["CONFIG_" vsec "_" name] == val) {
  81. # condition is met, check requirement
  82. if (!length(ENVIRON["CONFIG_" vsec "_" var])) {
  83. print STDERR "Error: missing config " \
  84. "option " var " in " vsec
  85. exit 1
  86. }
  87. }
  88. }
  89. }
  90. }
  91. # is_valid just returns true(1)/false(0) if the
  92. # given value is conform with the type definition
  93. # NOTE: this function needs the type validating function from
  94. # validate_config.awk
  95. #
  96. function is_valid(type,value) {
  97. # the enum type contains a definition of all allowed values as csv
  98. # e.g. enum,alpha,beta,gamma
  99. if (type ~ "enum" ) {
  100. split(type,tarr,",")
  101. for (num in tarr) {
  102. if (num > 0) {
  103. gsub("^[ \t\n]*","",tarr[num]);
  104. gsub("[ \t\n]*$","",tarr[num]);
  105. if (tarr[num] == value) {
  106. return 1
  107. }
  108. }
  109. }
  110. return 0;
  111. }
  112. # all other types are checked as defined in the former validate.awk
  113. if (type ~ "int") return is_int(value)
  114. if (type ~ "ip" ) return is_ip(value)
  115. if (type ~ "netmask" ) return is_netmask(value)
  116. if (type ~ "string" ) return is_string(value)
  117. if (type ~ "wep" ) return is_wep(value)
  118. if (type ~ "hostname" ) return is_hostname(value)
  119. if (type ~ "mac" ) return is_mac(value)
  120. if (type ~ "port" ) return is_port(value)
  121. if (type ~ "ports" ) return is_ports(value)
  122. if (type ~ "wpapsk" ) return is_wpapsk(value)
  123. }
  124. # validate_config compares the specification as parsed from the spec file
  125. # with the environment variables
  126. # CONFIG_SECTION contains the relevant config section name, e.g. wan
  127. # CONFIG_<section>_TYPE contains the type of the config, e.g. interface
  128. # CONFIG_<section>_<var> contains the value of the config option <var>
  129. #
  130. function validate_config() {
  131. # get the config section name
  132. vname=ENVIRON["CONFIG_SECTION"]
  133. if (!length(vname)) {
  134. print STDERR "Error: no current configuration"
  135. exit 1
  136. }
  137. # get the config section type
  138. vsec=ENVIRON["CONFIG_" vname "_TYPE"]
  139. if (!length(vsec)) {
  140. print STDERR "Error: section " vsec " not found"
  141. exit 1
  142. }
  143. # loop through all config options specified for this section type
  144. split(vars[vsec],options,",")
  145. for (oidx in options) {
  146. # first, look for all required attributes
  147. var=options[oidx]
  148. check_requirements(vname,var)
  149. # next look at each option and validate it
  150. val=ENVIRON["CONFIG_" vname "_" var]
  151. if (length(val)) {
  152. if (!is_valid(types[vsec "_" var],val)) {
  153. print "Error: type validation error for '" var "' in section '" vname "'"
  154. exit 1
  155. }
  156. }
  157. }
  158. }
  159. END {
  160. validate_config()
  161. }