run: target-specific config schemata

The run tool now by default checks configurations with target-specific
XML schemata. Each component may define a config schema file in its
target.mk via the CONFIG_XSD variable. When the run tool has checked an
configuration of an init instance, it additionally goes through the
start nodes of the config. For each start node it checks whether there
is an XSD file that matches. If so, the run tool also checks the config
of the start node (if existant). This is done recursively. I.e., also
the child configs of a sub-init of a sub-init of the top-level init
receive a config check.

Issue #2600
This commit is contained in:
Martin Stein 2017-12-03 18:48:40 +01:00 committed by Christian Helmuth
parent 568865bde0
commit fb2398dbf2
4 changed files with 113 additions and 9 deletions

View File

@ -173,6 +173,15 @@ LD_CMD += -Wl,--end-group
LD_LIBGCC ?= $(shell $(CC) $(CC_MARCH) -print-libgcc-file-name)
LD_CMD += $(LD_LIBGCC)
#
# If available, link XML schema file for checking configurations
#
ifneq ($(CONFIG_XSD),)
all: $(INSTALL_DIR)/$(TARGET).xsd
$(INSTALL_DIR)/$(TARGET).xsd: $(PRG_DIR)/$(CONFIG_XSD)
$(VERBOSE)ln -sf $< $@
endif
#
# Skip final linking if no objects are involved, i.e. no 'SRC' files are
# specified in the 'target.mk' file. This applies for pseudo 'target.mk'

View File

@ -2,3 +2,5 @@ TARGET = init
SRC_CC = main.cc child.cc server.cc
LIBS = base
INC_DIR += $(PRG_DIR)
CONFIG_XSD = config.xsd

View File

@ -106,22 +106,105 @@ proc check_xml_syntax {xml_file} {
##
# Validate file to match Genode's XML schema using xmllint
# Validate configuration file to match an XML schema using xmllint
#
proc check_xml_with_schema {xml_file} {
# \param bin binary name of the component behind the config
# \param xml_file configuration file
# \param xsd_file configuration schema file
# \param avail_xsd_files list of xsd files that might be used for
# configurations of children of the component
# \param nesting_level level of recursive calls of this procedure
#
proc check_config {bin xml_file xsd_file label avail_xsd_files nesting_level} {
if {![have_installed xmllint]} {
puts "Warning: Cannot validate config syntax (please install xmllint)"
return;
# check prerequisites if this is not a recursive call
if {$nesting_level == 0} {
if {![have_installed xmllint]} {
puts ""
puts "Warning: cannot validate config syntax\
(please install xmllint)"
puts ""
exit 1
}
}
if {[catch {exec xmllint --noout -schema [genode_dir]/tool/run/genode.xsd $xml_file} result]} {
# check the given component configuration itself
puts " CHECK $label"
if {[catch {exec xmllint --noout -schema $xsd_file $xml_file} result]} {
if {$result != "$xml_file validates"} {
puts stderr "$result"
puts stderr "Error: Invalid XML syntax in $xml_file"
puts stderr "Error: Invalid XML syntax"
exit 1
}
}
#
# If this is no instance of Genodes Init component, we can skip checking
# for potential child configurations.
#
if {$bin != "init"} {
return
}
#
# The names of the available XSD files tell us for which binaries we
# can do a check. So iterate through the XSD files and try to find
# corresponding child instances.
#
foreach child_xsd_file $avail_xsd_files {
set child_bin [file tail [file rootname $child_xsd_file]]
for {set child_instance 1} {1} {incr child_instance} {
#
# Try to find a child instance that uses this binary. We start
# with selecting the first matching start node, than the
# second, and so on. As soon as xmlscarlet returns an empty
# string, we know that there is no further matching start node.
#
set xpath_start_cond "child::binary\[@name=\'$child_bin\'\] or \
not(child::binary) and @name=\'$child_bin\'"
set xpath "string(/config/start\[$xpath_start_cond\]\[$child_instance\]/@name)"
set select_xpath "xmllint --xpath \"$xpath\" $xml_file"
if {[catch {exec {*}$select_xpath} child_name]} {
#
# No further child instance that uses this binary.
# Proceed with next binary.
#
break
}
#
# If the child has a config, check it with a recursive
# call to this procedure.
#
set xpath "/config/start\[$xpath_start_cond\]\[$child_instance\]/config"
set select_xpath "xmllint --xpath \"$xpath\" $xml_file"
if {[catch {exec {*}$select_xpath} child_xml]} {
# the child has no config
break
}
# write child config to temporary file
set child_xml_file ".config_$nesting_level.xml.tmp"
set child_xml_fd [open $child_xml_file w]
puts $child_xml_fd $child_xml
close $child_xml_fd
# call this procedure again on the child config file
set child_label "$label -> $child_name"
check_config $child_bin $child_xml_file $child_xsd_file \
$child_label $avail_xsd_files [expr $nesting_level+1]
# clean up
exec rm -f $child_xml_file
}
}
}
@ -132,8 +215,6 @@ proc install_config { args } {
set fh [open "[run_dir]/genode/config" "WRONLY CREAT TRUNC"]
puts $fh [join $args {}]
close $fh
check_xml_with_schema [run_dir]/genode/config
}
@ -144,6 +225,18 @@ proc install_config { args } {
# '<build-dir>/bin/' directory
#
proc build_boot_image {binaries} {
# lookup available XSD files
set xsd_files ""
foreach binary $binaries {
if {[file exists "bin/$binary.xsd"]} {
lappend xsd_files "bin/$binary.xsd"
}
}
# apply the found XSD files
puts "checking configuration syntax"
check_config init [run_dir]/genode/config bin/init.xsd init $xsd_files 0
check_for_missing_depot_archives
run_boot_dir $binaries
}