diff --git a/repos/os/include/init/child.h b/repos/os/include/init/child.h index cdac89697..546d64122 100644 --- a/repos/os/include/init/child.h +++ b/repos/os/include/init/child.h @@ -178,17 +178,12 @@ namespace Init { if (!service_matches) return false; - if (!service_node.has_attribute("label")) - return true; - - typedef Genode::String<160> Label; - - Label const expected = service_node.attribute_value("label", Label()); + typedef Genode::String<128> Label; Label const session_label = Label(skip_label_prefix(child_name, Genode::Session_label(args).string())); - return session_label == expected; + return !Genode::Xml_node_label_score(service_node, session_label).conflict(); } diff --git a/repos/os/include/os/session_policy.h b/repos/os/include/os/session_policy.h index 664a12a2c..d1df2d38b 100644 --- a/repos/os/include/os/session_policy.h +++ b/repos/os/include/os/session_policy.h @@ -5,7 +5,7 @@ */ /* - * Copyright (C) 2011-2013 Genode Labs GmbH + * Copyright (C) 2011-2015 Genode Labs GmbH * * This file is part of the Genode OS framework, which is distributed * under the terms of the GNU General Public License version 2. @@ -19,11 +19,136 @@ namespace Genode { + struct Xml_node_label_score; struct Session_label; class Session_policy; } +/** + * Score for matching an Xml_node against a label + * + * The score is based on the attributes 'label', 'label_prefix', and + * 'label_suffix'. + */ +struct Genode::Xml_node_label_score +{ + bool label_present = true; + bool prefix_present = true; + bool suffix_present = true; + + bool label_match = false; + + /* + * The match values contain the number of matching characters + 1. + * If 0, there is a conflict. If 1, an empty string matched. + */ + enum { CONFLICT = 0 }; + unsigned prefix_match = CONFLICT; + unsigned suffix_match = CONFLICT; + + Xml_node_label_score() { } + + template + Xml_node_label_score(Xml_node node, String const &label) + : + label_present (node.has_attribute("label")), + prefix_present(node.has_attribute("label_prefix")), + suffix_present(node.has_attribute("label_suffix")) + { + if (label_present) + label_match = node.attribute_value("label", String()) == label; + + if (prefix_present) { + typedef String Prefix; + Prefix const prefix = node.attribute_value("label_prefix", Prefix()); + + if (!strcmp(label.string(), prefix.string(), prefix.length() - 1)) + prefix_match = prefix.length(); + } + + if (suffix_present) { + typedef String Suffix; + Suffix const suffix = node.attribute_value("label_suffix", Suffix()); + + if (label.length() >= suffix.length()) { + unsigned const offset = label.length() - suffix.length(); + + if (!strcmp(label.string() + offset, suffix.string())) + suffix_match = suffix.length(); + } + } + } + + bool conflict() const + { + return (label_present && !label_match) + || (prefix_present && !prefix_match) + || (suffix_present && !suffix_match); + } + + /** + * Return true if this node's score is higher than 'other' + */ + bool stronger(Xml_node_label_score const &other) const + { + /* if we are in conflict, we have a lower score than any other node */ + if (conflict()) + return false; + + /* there are no conflicts */ + + /* we have a higher score than another conflicting node */ + if (other.conflict()) + return true; + + if (label_present && !other.label_present) + return true; + + if (other.label_present) + return false; + + /* labels are equally good */ + + if (prefix_present && !other.prefix_present) + return true; + + if (!prefix_present && other.prefix_present) + return false; + + if (prefix_present && other.prefix_present) { + + if (prefix_match > other.prefix_match) + return true; + + if (prefix_match < other.prefix_match) + return false; + } + + /* prefixes are equally good */ + + if (suffix_present && !other.suffix_present) + return true; + + if (!suffix_present && other.suffix_present) + return false; + + if (suffix_present && other.suffix_present) { + + if (suffix_match > other.suffix_match) + return true; + + if (suffix_match < other.suffix_match) + return false; + } + + /* nodes are equally good */ + + return false; + } +}; + + struct Genode::Session_label : String<128> { Session_label() { } @@ -62,41 +187,27 @@ class Genode::Session_policy : public Xml_node private: - /** - * Returns true if the start of the label matches the specified - * match string - */ - static bool _label_matches(char const *label, char const *match) { - return strcmp(label, match, strlen(match)) == 0; } - /** * Query session policy from session label */ - static Xml_node _query_policy(char const *label, Xml_node config) + template + static Xml_node _query_policy(String const &label, Xml_node config) { /* * Find policy node that matches best */ - Xml_node best_match(""); - - unsigned label_len = 0; + Xml_node best_match(""); + Xml_node_label_score best_score; /* * Functor to be applied to each policy node */ auto lambda = [&] (Xml_node policy) { - - /* label attribute from policy node */ - char policy_label[Session_label::capacity()]; - policy.attribute("label").value(policy_label, - sizeof(policy_label)); - - if (!_label_matches(label, policy_label) - || strlen(policy_label) < label_len) - return; - - label_len = strlen(policy_label); - best_match = policy; + Xml_node_label_score const score(policy, label); + if (score.stronger(best_score)) { + best_match = policy; + best_score = score; + } }; config.for_each_sub_node("policy", lambda); @@ -132,7 +243,7 @@ class Genode::Session_policy : public Xml_node explicit Session_policy(String const &label, Xml_node config = Genode::config()->xml_node()) : - Xml_node(_query_policy(label.string(), config)) + Xml_node(_query_policy(label, config)) { } };