diff --git a/repos/gems/run/depot_query.run b/repos/gems/run/depot_query.run
index 5d1f1731ae..81d8db046e 100644
--- a/repos/gems/run/depot_query.run
+++ b/repos/gems/run/depot_query.run
@@ -43,7 +43,8 @@ install_config {
-
+
+
@@ -64,20 +65,18 @@ install_config {
-
+
-
-
-
-
-
-
+
+
+
+
-
+
@@ -95,6 +94,7 @@ install_config {
+
@@ -102,7 +102,7 @@ install_config {
-
+
diff --git a/repos/gems/src/app/depot_deploy/child.h b/repos/gems/src/app/depot_deploy/child.h
new file mode 100644
index 0000000000..c460030dca
--- /dev/null
+++ b/repos/gems/src/app/depot_deploy/child.h
@@ -0,0 +1,294 @@
+/*
+ * \brief Child representation
+ * \author Norman Feske
+ * \date 2018-01-23
+ */
+
+/*
+ * Copyright (C) 2018 Genode Labs GmbH
+ *
+ * This file is part of the Genode OS framework, which is distributed
+ * under the terms of the GNU Affero General Public License version 3.
+ */
+
+#ifndef _CHILD_H_
+#define _CHILD_H_
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+
+namespace Depot_deploy {
+ using namespace Depot;
+ struct Child;
+}
+
+
+class Depot_deploy::Child : public List_model::Element
+{
+ public:
+
+ typedef String<100> Name;
+ typedef String<80> Binary_name;
+ typedef String<80> Config_name;
+
+ private:
+
+ Allocator &_alloc;
+
+ Reconstructible _start_xml; /* from config */
+ Constructible _pkg_xml { }; /* from blueprint */
+
+ Name const _name;
+
+ Archive::Path _config_pkg_path() const
+ {
+ return _start_xml->xml().attribute_value("pkg", Archive::Path());
+ }
+
+ /*
+ * The pkg-archive path of the current blueprint query, which may
+ * deviate from pkg path given in the config, once the config is
+ * updated.
+ */
+ Archive::Path _blueprint_pkg_path = _config_pkg_path();
+
+ Ram_quota _ram_quota { 0 };
+ Cap_quota _cap_quota { 0 };
+ Binary_name _binary_name { };
+ Config_name _config_name { };
+
+ bool _configured() const
+ {
+ return _pkg_xml.constructed()
+ && (_config_pkg_path() == _blueprint_pkg_path);
+ }
+
+ inline void _gen_routes(Xml_generator &, Xml_node common) const;
+
+ static void _gen_provides_sub_node(Xml_generator &xml, Xml_node service,
+ Xml_node::Type const &node_type,
+ Service::Name const &service_name)
+ {
+ if (service.type() == node_type)
+ xml.node("service", [&] () {
+ xml.attribute("name", service_name); });
+ }
+
+ static void _gen_copy_of_sub_node(Xml_generator &xml, Xml_node from_node,
+ Xml_node::Type const &sub_node_type)
+ {
+ if (!from_node.has_sub_node(sub_node_type.string()))
+ return;
+
+ Xml_node const sub_node = from_node.sub_node(sub_node_type.string());
+ xml.append(sub_node.addr(), sub_node.size());
+ }
+
+ public:
+
+ Child(Allocator &alloc, Xml_node start_node)
+ :
+ _alloc(alloc),
+ _start_xml(_alloc, start_node),
+ _name(_start_xml->xml().attribute_value("name", Name()))
+ { }
+
+ Name name() const { return _name; }
+
+ void apply_config(Xml_node start_node)
+ {
+ /*
+ * String-compare new with current start node to quicky skip
+ * the start nodes that have not changed.
+ */
+ bool const start_node_changed =
+ (start_node.size() != _start_xml->xml().size()) ||
+ (strcmp(start_node.addr(), _start_xml->xml().addr(),
+ start_node.size()) != 0);
+
+ if (!start_node_changed)
+ return;
+
+ Archive::Path const pkg =
+ start_node.attribute_value("pkg", Archive::Path());
+
+ /* invalidate blueprint if 'pkg' attribute of start node changed */
+ if (pkg != _config_pkg_path())
+ _pkg_xml.destruct();
+
+ /* import new start node */
+ _start_xml.construct(_alloc, start_node);
+ }
+
+ void apply_blueprint(Xml_node pkg)
+ {
+ if (pkg.attribute_value("path", Archive::Path()) != _blueprint_pkg_path)
+ return;
+
+ Xml_node const runtime = pkg.sub_node("runtime");
+
+ _ram_quota = Ram_quota { runtime.attribute_value("ram", Number_of_bytes()) };
+ _cap_quota = Cap_quota { runtime.attribute_value("caps", 0UL) };
+
+ _binary_name = runtime.attribute_value("binary", Binary_name());
+ _config_name = runtime.attribute_value("config", Config_name());
+
+ /* keep copy of the blueprint info */
+ _pkg_xml.construct(_alloc, pkg);
+ }
+
+ void gen_query(Xml_generator &xml) const
+ {
+ if (_configured())
+ return;
+
+ xml.node("blueprint", [&] () {
+ xml.attribute("pkg", _blueprint_pkg_path); });
+ }
+
+ /**
+ * Generate start node of init configuration
+ *
+ * \param common session routes to be added in addition to the ones
+ * found in the pkg blueprint
+ */
+ inline void gen_start_node(Xml_generator &, Xml_node common) const;
+};
+
+
+void Depot_deploy::Child::gen_start_node(Xml_generator &xml, Xml_node common) const
+{
+ if (!_configured())
+ return;
+
+ if (!_pkg_xml->xml().has_sub_node("runtime")) {
+ warning("blueprint for '", _name, "' lacks runtime information");
+ return;
+ }
+
+ xml.node("start", [&] () {
+
+ xml.attribute("name", _name);
+ xml.attribute("caps", _cap_quota.value);
+
+ xml.node("binary", [&] () { xml.attribute("name", _binary_name); });
+
+ xml.node("resource", [&] () {
+ xml.attribute("name", "RAM");
+ xml.attribute("quantum", String<32>(Number_of_bytes(_ram_quota.value)));
+ });
+
+ Xml_node const runtime = _pkg_xml->xml().sub_node("runtime");
+
+ /*
+ * Insert inline '' node if provided by the start node or the
+ * blueprint. The former is preferred over the latter.
+ */
+ if (_start_xml->xml().has_sub_node("config")) {
+ _gen_copy_of_sub_node(xml, _start_xml->xml(), "config");
+ } else {
+ if (runtime.has_sub_node("config"))
+ _gen_copy_of_sub_node(xml, runtime, "config");
+ }
+
+ /*
+ * Declare services provided by the subsystem.
+ */
+ if (runtime.has_sub_node("provides")) {
+ xml.node("provides", [&] () {
+ runtime.sub_node("provides").for_each_sub_node([&] (Xml_node service) {
+ _gen_provides_sub_node(xml, service, "rom", "ROM");
+ _gen_provides_sub_node(xml, service, "log", "LOG");
+ _gen_provides_sub_node(xml, service, "timer", "Timer");
+ _gen_provides_sub_node(xml, service, "block", "Block");
+ _gen_provides_sub_node(xml, service, "report", "Report");
+ _gen_provides_sub_node(xml, service, "nic", "Nic");
+ _gen_provides_sub_node(xml, service, "nitpicker", "Nitpicker");
+ _gen_provides_sub_node(xml, service, "framebuffer", "Framebuffer");
+ _gen_provides_sub_node(xml, service, "input", "Input");
+ _gen_provides_sub_node(xml, service, "audio_out", "Audio_out");
+ _gen_provides_sub_node(xml, service, "audio_in", "Audio_in");
+ _gen_provides_sub_node(xml, service, "file_system", "File_system");
+ });
+ });
+ }
+
+ xml.node("route", [&] () { _gen_routes(xml, common); });
+ });
+}
+
+
+void Depot_deploy::Child::_gen_routes(Xml_generator &xml, Xml_node common) const
+{
+ if (!_pkg_xml.constructed())
+ return;
+
+ typedef String<160> Path;
+
+ /*
+ * Add routes given in the start node.
+ */
+ if (_start_xml->xml().has_sub_node("route")) {
+ Xml_node const route = _start_xml->xml().sub_node("route");
+ xml.append(route.content_base(), route.content_size());
+ }
+
+ /*
+ * Redirect config ROM request to label as given in the 'config' attribute,
+ * if present. We need to search the blueprint's nodes for the
+ * matching ROM module to rewrite the label with the configuration's path
+ * within the depot.
+ */
+ if (_config_name.valid()) {
+ _pkg_xml->xml().for_each_sub_node("rom", [&] (Xml_node rom) {
+
+ if (!rom.has_attribute("path"))
+ return;
+
+ if (rom.attribute_value("label", Name()) != _config_name)
+ return;
+
+ /* we found the node for the config ROM */
+ xml.node("service", [&] () {
+ xml.attribute("name", "ROM");
+ xml.attribute("label", "config");
+ xml.node("parent", [&] () {
+ typedef String<160> Path;
+ xml.attribute("label", rom.attribute_value("path", Path()));
+ });
+ });
+ });
+ }
+
+ /*
+ * Add common routes as defined in our config.
+ */
+ xml.append(common.content_base(), common.content_size());
+
+ /*
+ * Add ROM routing rule with the label rewritten to the path within the
+ * depot.
+ */
+ _pkg_xml->xml().for_each_sub_node("rom", [&] (Xml_node rom) {
+
+ if (!rom.has_attribute("path"))
+ return;
+
+ typedef Name Label;
+ Path const path = rom.attribute_value("path", Path());
+ Label const label = rom.attribute_value("label", Label());
+
+ xml.node("service", [&] () {
+ xml.attribute("name", "ROM");
+ xml.attribute("label_last", label);
+ xml.node("parent", [&] () {
+ xml.attribute("label", path); });
+ });
+ });
+}
+
+#endif /* _CHILD_H_ */
diff --git a/repos/gems/src/app/depot_deploy/main.cc b/repos/gems/src/app/depot_deploy/main.cc
index df8445bab8..5b947421d1 100644
--- a/repos/gems/src/app/depot_deploy/main.cc
+++ b/repos/gems/src/app/depot_deploy/main.cc
@@ -12,16 +12,83 @@
*/
/* Genode includes */
+#include
#include
#include
+#include
#include
+/* local includes */
+#include "child.h"
+
namespace Depot_deploy {
- using namespace Genode;
+ struct Children;
struct Main;
}
+class Depot_deploy::Children
+{
+ private:
+
+ Allocator &_alloc;
+
+ List_model _children { };
+
+ struct Model_update_policy : List_model::Update_policy
+ {
+ Allocator &_alloc;
+
+ Model_update_policy(Allocator &alloc) : _alloc(alloc) { }
+
+ void destroy_element(Child &c) { destroy(_alloc, &c); }
+
+ Child &create_element(Xml_node node)
+ {
+ return *new (_alloc) Child(_alloc, node);
+ }
+
+ void update_element(Child &c, Xml_node node) { c.apply_config(node); }
+
+ static bool element_matches_xml_node(Child const &child, Xml_node node)
+ {
+ return node.attribute_value("name", Child::Name()) == child.name();
+ }
+
+ static bool node_is_element(Xml_node node) { return node.has_type("start"); }
+
+ } _model_update_policy { _alloc };
+
+ public:
+
+ Children(Allocator &alloc) : _alloc(alloc) { }
+
+ void apply_config(Xml_node config)
+ {
+ _children.update_from_xml(_model_update_policy, config);
+ }
+
+ void apply_blueprint(Xml_node blueprint)
+ {
+ blueprint.for_each_sub_node("pkg", [&] (Xml_node pkg) {
+ _children.for_each([&] (Child &child) {
+ child.apply_blueprint(pkg); }); });
+ }
+
+ void gen_start_nodes(Xml_generator &xml, Xml_node common)
+ {
+ _children.for_each([&] (Child const &child) {
+ child.gen_start_node(xml, common); });
+ }
+
+ void gen_queries(Xml_generator &xml)
+ {
+ _children.for_each([&] (Child const &child) {
+ child.gen_query(xml); });
+ }
+};
+
+
struct Depot_deploy::Main
{
Env &_env;
@@ -29,67 +96,55 @@ struct Depot_deploy::Main
Attached_rom_dataspace _config { _env, "config" };
Attached_rom_dataspace _blueprint { _env, "blueprint" };
- Reporter _init_config_reporter { _env, "config", "init.config", 16*1024 };
+ Expanding_reporter _query_reporter { _env, "query" , "query"};
+ Expanding_reporter _init_config_reporter { _env, "config", "init.config"};
+
+ size_t _query_buffer_size = 4096;
+ size_t _init_config_buffer_size = 4096;
+
+ Heap _heap { _env.ram(), _env.rm() };
+
+ Children _children { _heap };
Signal_handler _config_handler {
_env.ep(), *this, &Main::_handle_config };
typedef String<128> Name;
- typedef String<80> Binary;
- typedef String<80> Config;
-
- /**
- * Generate start node of init configuration
- *
- * \param pkg pkg node of the subsystem blueprint
- * \param common session routes to be added in addition to the ones
- * found in the pkg blueprint
- */
- static void _gen_start_node(Xml_generator &, Xml_node pkg, Xml_node common);
void _handle_config()
{
_config.update();
_blueprint.update();
- Xml_node const config = _config.xml();
- Xml_node const blueprint = _blueprint.xml();
+ Xml_node const config = _config.xml();
- Reporter::Xml_generator xml(_init_config_reporter, [&] () {
+ _children.apply_config(config);
+ _children.apply_blueprint(_blueprint.xml());
+ /* determine CPU architecture of deployment */
+ typedef String<16> Arch;
+ Arch const arch = config.attribute_value("arch", Arch());
+ if (!arch.valid())
+ warning("config lacks 'arch' attribute");
+
+ /* generate init config containing all configured start nodes */
+ _init_config_reporter.generate([&] (Xml_generator &xml) {
Xml_node static_config = config.sub_node("static");
xml.append(static_config.content_base(), static_config.content_size());
-
- blueprint.for_each_sub_node("pkg", [&] (Xml_node pkg) {
-
- /*
- * Check preconditions for generating a '' node.
- */
- Name const name = pkg.attribute_value("name", Name());
-
- if (!pkg.has_sub_node("runtime")) {
- warning(" node for '", name, "' lacks node");
- return;
- }
-
- Xml_node const runtime = pkg.sub_node("runtime");
-
- if (!runtime.has_attribute("binary")) {
- warning(" node for '", name, "' lacks 'binary' attribute");
- return;
- }
-
- xml.node("start", [&] () {
- _gen_start_node(xml, pkg, config.sub_node("common_routes"));
- });
- });
+ _children.gen_start_nodes(xml, config.sub_node("common_routes"));
});
+
+ /* update query for blueprints of all unconfigured start nodes */
+ if (arch.valid()) {
+ _query_reporter.generate([&] (Xml_generator &xml) {
+ xml.attribute("arch", arch);
+ _children.gen_queries(xml);
+ });
+ }
}
Main(Env &env) : _env(env)
{
- _init_config_reporter.enabled(true);
-
_config .sigh(_config_handler);
_blueprint.sigh(_config_handler);
@@ -98,80 +153,5 @@ struct Depot_deploy::Main
};
-void Depot_deploy::Main::_gen_start_node(Xml_generator &xml, Xml_node pkg, Xml_node common)
-{
- typedef String<80> Name;
-
- Name const name = pkg.attribute_value("name", Name());
- Xml_node const runtime = pkg.sub_node("runtime");
- size_t const caps = runtime.attribute_value("caps", 0UL);
- Number_of_bytes const ram = runtime.attribute_value("ram", Number_of_bytes());
- Binary const binary = runtime.attribute_value("binary", Binary());
- Config const config = runtime.attribute_value("config", Config());
-
- xml.attribute("name", name);
- xml.attribute("caps", caps);
-
- xml.node("binary", [&] () { xml.attribute("name", binary); });
-
- xml.node("resource", [&] () {
- xml.attribute("name", "RAM");
- xml.attribute("quantum", String<32>(ram));
- });
-
- /*
- * Insert inline '' node if provided by the blueprint.
- */
- if (runtime.has_sub_node("config")) {
- Xml_node config = runtime.sub_node("config");
- xml.node("config", [&] () {
- xml.append(config.content_base(), config.content_size()); });
- };
-
- xml.node("route", [&] () {
-
- /*
- * Redirect config ROM request to label given in the 'config'
- * attribute.
- */
- if (config.valid()) {
- xml.node("service", [&] () {
- xml.attribute("name", "ROM");
- xml.attribute("label", "config");
- xml.node("parent", [&] () {
- xml.attribute("label", config); });
- });
- }
-
- /*
- * Add common routes as defined in our config.
- */
- xml.append(common.content_base(), common.content_size());
-
- /*
- * Add ROM routing rule with the label rewritten to
- * the path within the depot.
- */
- pkg.for_each_sub_node("rom", [&] (Xml_node rom) {
-
- if (!rom.has_attribute("path"))
- return;
-
- typedef String<160> Path;
- typedef Name Label;
- Path const path = rom.attribute_value("path", Path());
- Label const label = rom.attribute_value("label", Label());
-
- xml.node("service", [&] () {
- xml.attribute("name", "ROM");
- xml.attribute("label_last", label);
- xml.node("parent", [&] () {
- xml.attribute("label", path); });
- });
- });
- });
-}
-
-
void Component::construct(Genode::Env &env) { static Depot_deploy::Main main(env); }
diff --git a/repos/gems/src/app/depot_deploy/target.mk b/repos/gems/src/app/depot_deploy/target.mk
index 5064cc00a6..cb84c2cd49 100644
--- a/repos/gems/src/app/depot_deploy/target.mk
+++ b/repos/gems/src/app/depot_deploy/target.mk
@@ -1,5 +1,3 @@
TARGET = depot_deploy
SRC_CC = main.cc
-LIBS += base vfs
-
-CC_CXX_WARN_STRICT =
+LIBS += base
diff --git a/repos/gems/src/app/depot_query/main.cc b/repos/gems/src/app/depot_query/main.cc
index 7e58ded975..0a4e78883e 100644
--- a/repos/gems/src/app/depot_query/main.cc
+++ b/repos/gems/src/app/depot_query/main.cc
@@ -161,10 +161,25 @@ struct Depot_query::Main
Signal_handler _config_handler {
_env.ep(), *this, &Main::_handle_config };
- Reporter _directory_reporter { _env, "directory" };
- Reporter _blueprint_reporter { _env, "blueprint" };
- Reporter _dependencies_reporter { _env, "dependencies" };
- Reporter _user_reporter { _env, "user" };
+ Signal_handler _query_handler {
+ _env.ep(), *this, &Main::_handle_config };
+
+ typedef Constructible Constructible_reporter;
+
+ Constructible_reporter _directory_reporter { _env, "directory" };
+ Constructible_reporter _blueprint_reporter { _env, "blueprint" };
+ Constructible_reporter _dependencies_reporter { _env, "dependencies" };
+ Constructible_reporter _user_reporter { _env, "user" };
+
+ template
+ static void _construct_if(bool condition, Constructible &obj, ARGS &&... args)
+ {
+ if (condition && !obj.constructed())
+ obj.construct(args...);
+
+ if (!condition && obj.constructed())
+ obj.destruct();
+ }
typedef String<64> Rom_label;
typedef String<16> Architecture;
@@ -205,7 +220,7 @@ struct Depot_query::Main
if (query_from_rom && !_query_rom.constructed()) {
_query_rom.construct(_env, "query");
- _query_rom->sigh(_config_handler);
+ _query_rom->sigh(_query_handler);
}
if (!query_from_rom && _query_rom.constructed())
@@ -216,20 +231,31 @@ struct Depot_query::Main
Xml_node const query = (query_from_rom ? _query_rom->xml() : config);
- _directory_reporter .enabled(query.has_sub_node("scan"));
- _blueprint_reporter .enabled(query.has_sub_node("blueprint"));
- _dependencies_reporter.enabled(query.has_sub_node("dependencies"));
- _user_reporter .enabled(query.has_sub_node("user"));
+ _construct_if(query.has_sub_node("scan"),
+ _directory_reporter, _env, "directory", "directory");
+
+ _construct_if(query.has_sub_node("blueprint"),
+ _blueprint_reporter, _env, "blueprint", "blueprint");
+
+ _construct_if(query.has_sub_node("dependencies"),
+ _dependencies_reporter, _env, "dependencies", "dependencies");
+
+ _construct_if(query.has_sub_node("user"),
+ _user_reporter, _env, "user", "user");
_root.apply_config(config.sub_node("vfs"));
+ /* ignore incomplete queries that may occur at the startup */
+ if (query.has_type("empty"))
+ return;
+
if (!query.has_attribute("arch"))
warning("query lacks 'arch' attribute");
_architecture = query.attribute_value("arch", Architecture());
- if (_directory_reporter.enabled()) {
- Reporter::Xml_generator xml(_directory_reporter, [&] () {
+ if (_directory_reporter.constructed()) {
+ _directory_reporter->generate([&] (Xml_generator &xml) {
query.for_each_sub_node("scan", [&] (Xml_node node) {
Archive::User const user = node.attribute_value("user", Archive::User());
Directory::Path path("depot/", user, "/pkg");
@@ -239,11 +265,13 @@ struct Depot_query::Main
});
}
- if (_blueprint_reporter.enabled()) {
- Reporter::Xml_generator xml(_blueprint_reporter, [&] () {
+ if (_blueprint_reporter.constructed()) {
+ _blueprint_reporter->generate([&] (Xml_generator &xml) {
query.for_each_sub_node("blueprint", [&] (Xml_node node) {
Archive::Path pkg = node.attribute_value("pkg", Archive::Path());
try { _query_blueprint(pkg, xml); }
+ catch (Xml_generator::Buffer_exceeded) {
+ throw; /* handled by 'generate' */ }
catch (...) {
warning("could not obtain blueprint for '", pkg, "'");
}
@@ -251,8 +279,8 @@ struct Depot_query::Main
});
}
- if (_dependencies_reporter.enabled()) {
- Reporter::Xml_generator xml(_dependencies_reporter, [&] () {
+ if (_dependencies_reporter.constructed()) {
+ _dependencies_reporter->generate([&] (Xml_generator &xml) {
Dependencies dependencies(_heap, _depot_dir);
query.for_each_sub_node("dependencies", [&] (Xml_node node) {
@@ -268,8 +296,8 @@ struct Depot_query::Main
});
}
- if (_user_reporter.enabled()) {
- Reporter::Xml_generator xml(_user_reporter, [&] () {
+ if (_user_reporter.constructed()) {
+ _user_reporter->generate([&] (Xml_generator &xml) {
query.for_each_sub_node("user", [&] (Xml_node node) {
_query_user(node.attribute_value("name", Archive::User()), xml); });
});