diff --git a/repos/gems/include/gems/vfs.h b/repos/gems/include/gems/vfs.h
new file mode 100644
index 0000000000..3277be04b2
--- /dev/null
+++ b/repos/gems/include/gems/vfs.h
@@ -0,0 +1,345 @@
+/*
+ * \brief Front-end API for accessing a component-local virtual file system
+ * \author Norman Feske
+ * \date 2017-07-04
+ */
+
+/*
+ * Copyright (C) 2017 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 _INCLUDE__GEMS__VFS_H_
+#define _INCLUDE__GEMS__VFS_H_
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+
+namespace Genode {
+ struct Directory;
+ struct Root_directory;
+ struct File;
+ struct Readonly_file;
+ struct File_content;
+}
+
+
+struct Genode::Directory : Noncopyable
+{
+ public:
+
+ struct Open_failed : Exception { };
+ struct Read_dir_failed : Exception { };
+
+ class Entry
+ {
+ private:
+
+ Vfs::Directory_service::Dirent _dirent;
+
+ friend class Directory;
+
+ Entry() { }
+
+ public:
+
+ void print(Output &out) const
+ {
+ using Genode::print;
+ using Vfs::Directory_service;
+
+ print(out, _dirent.name, " (");
+ switch (_dirent.type) {
+ case Directory_service::DIRENT_TYPE_FILE: print(out, "file"); break;
+ case Directory_service::DIRENT_TYPE_DIRECTORY: print(out, "dir"); break;
+ case Directory_service::DIRENT_TYPE_SYMLINK: print(out, "symlink"); break;
+ default: print(out, "other"); break;
+ }
+ print(out, ")");
+ }
+
+ typedef String Name;
+
+ Name name() const { return Name(Cstring(_dirent.name)); }
+ };
+
+ typedef String<256> Path;
+
+ private:
+
+ Path const _path;
+
+ Vfs::File_system &_fs;
+
+ Allocator &_alloc;
+
+ friend class Readonly_file;
+ friend class Root_directory;
+
+ /**
+ * Constructor used by 'Root_directory'
+ *
+ * \throw Open_failed
+ */
+ Directory(Vfs::File_system &fs, Allocator &alloc, Path const &path)
+ : _path(""), _fs(fs), _alloc(alloc)
+ { }
+
+ /*
+ * Operations such as 'file_size' that are expected to be 'const' at
+ * the API level, do internally require I/O with the outside world,
+ * with involves non-const access to the VFS. This helper allows a
+ * 'const' method to perform I/O at the VFS.
+ */
+ Vfs::File_system &_nonconst_fs() const
+ {
+ return const_cast(_fs);
+ }
+
+ Vfs::Directory_service::Stat _stat(Path const &rel_path) const
+ {
+ Vfs::Directory_service::Stat stat;
+
+ /*
+ * Ignore return value as the validity of the result is can be
+ * checked by the caller via 'stat.mode != 0'.
+ */
+ _nonconst_fs().stat(Path(_path, "/", rel_path).string(), stat);
+ return stat;
+ }
+
+ public:
+
+ struct Nonexistent_file : Exception { };
+ struct Nonexistent_directory : Exception { };
+
+ /**
+ * Open sub directory
+ *
+ * \throw Nonexistent_directory
+ */
+ Directory(Directory &other, Path const &rel_path)
+ : _path(other._path, "/", rel_path), _fs(other._fs), _alloc(other._alloc)
+ {
+ if (!(other._stat(rel_path).mode & Vfs::Directory_service::STAT_MODE_DIRECTORY))
+ throw Nonexistent_directory();
+ }
+
+ template
+ void for_each_entry(FN const &fn)
+ {
+ for (unsigned i = 0;; i++) {
+
+ Entry entry;
+
+ Vfs::Directory_service::Dirent_result dirent_result =
+ _fs.dirent(_path.string(), i, entry._dirent);
+
+ if (dirent_result != Vfs::Directory_service::DIRENT_OK) {
+ error("could not access directory '", _path, "'");
+ throw Read_dir_failed();
+ }
+
+ if (entry._dirent.type == Vfs::Directory_service::DIRENT_TYPE_END)
+ return;
+
+ fn(entry);
+ }
+ }
+
+ bool file_exists(Path const &rel_path) const
+ {
+ return _stat(rel_path).mode & Vfs::Directory_service::STAT_MODE_FILE;
+ }
+
+ /**
+ * Return size of file at specified directory-relative path
+ *
+ * \throw Nonexistent_file file at path does not exist or
+ * the access to the file is denied
+ *
+ */
+ Vfs::file_size file_size(Path const &rel_path) const
+ {
+ Vfs::Directory_service::Stat stat = _stat(rel_path);
+ if (!(stat.mode & Vfs::Directory_service::STAT_MODE_FILE))
+ throw Nonexistent_file();
+
+ return stat.size;
+ }
+};
+
+
+struct Genode::Root_directory : public Vfs::Io_response_handler,
+ private Vfs::Global_file_system_factory,
+ private Vfs::Dir_file_system,
+ public Directory
+{
+ void handle_io_response(Vfs::Vfs_handle::Context*) override { }
+
+ Root_directory(Env &env, Allocator &alloc, Xml_node config)
+ :
+ Vfs::Global_file_system_factory(alloc),
+ Vfs::Dir_file_system(env, alloc, config, *this, *this),
+ Directory(*this, alloc, "/")
+ { }
+
+ void apply_config(Xml_node config) { Vfs::Dir_file_system::apply_config(config); }
+};
+
+
+struct Genode::File : Noncopyable
+{
+ struct Open_failed : Exception { };
+
+ struct Truncated_during_read : Exception { };
+
+ typedef Directory::Path Path;
+};
+
+
+class Genode::Readonly_file : public File
+{
+ private:
+
+ Vfs::Vfs_handle *_handle = nullptr;
+
+ void _open(Vfs::File_system &fs, Allocator &alloc, Path const path)
+ {
+ Vfs::Directory_service::Open_result res =
+ fs.open(path.string(), Vfs::Directory_service::OPEN_MODE_RDONLY,
+ &_handle, alloc);
+
+ if (res != Vfs::Directory_service::OPEN_OK) {
+ error("failed to open file '", path, "'");
+ throw Open_failed();
+ }
+ }
+
+ public:
+
+ /**
+ * Constructor
+ *
+ * \throw File::Open_failed
+ */
+ Readonly_file(Directory &dir, Path const &rel_path)
+ {
+ _open(dir._fs, dir._alloc, Path(dir._path, "/", rel_path));
+ }
+
+ ~Readonly_file() { _handle->ds().close(_handle); }
+
+ /**
+ * Read number of 'bytes' from file into local memory buffer 'dst'
+ *
+ * \throw Truncated_during_read
+ */
+ size_t read(char *dst, size_t bytes)
+ {
+ Vfs::file_size out_count = 0;
+ Vfs::File_io_service::Read_result const result =
+ _handle->fs().read(_handle, dst, bytes, out_count);
+
+ /*
+ * XXX handle READ_ERR_AGAIN, READ_ERR_WOULD_BLOCK, READ_QUEUED
+ */
+
+ if (result != Vfs::File_io_service::READ_OK)
+ throw Truncated_during_read();
+
+ return out_count;
+ }
+};
+
+
+class Genode::File_content
+{
+ private:
+
+ Allocator &_alloc;
+ size_t const _size;
+
+ char *_buffer = (char *)_alloc.alloc(_size);
+
+ public:
+
+ typedef Directory::Nonexistent_file Nonexistent_file;
+ typedef File::Truncated_during_read Truncated_during_read;
+
+ typedef Directory::Path Path;
+
+ struct Limit { size_t value; };
+
+ /**
+ * Constructor
+ *
+ * \throw Nonexistent_file
+ * \throw Truncated_during_read number of readable bytes differs
+ * from file status information
+ */
+ File_content(Allocator &alloc, Directory &dir, Path const &rel_path,
+ Limit limit)
+ :
+ _alloc(alloc),
+ _size(min(dir.file_size(rel_path), (Vfs::file_size)limit.value))
+ {
+ if (Readonly_file(dir, rel_path).read(_buffer, _size) != _size)
+ throw Truncated_during_read();
+ }
+
+ ~File_content() { _alloc.free(_buffer, _size); }
+
+ /**
+ * Call functor 'fn' with content as 'Xml_node' argument
+ *
+ * If the file does not contain valid XML, 'fn' is called with an
+ * '' node as argument.
+ */
+ template
+ void xml(FN const &fn) const
+ {
+ try { fn(Xml_node(_buffer, _size)); }
+ catch (Xml_node::Invalid_syntax) { fn(Xml_node("")); }
+ }
+
+ /**
+ * Call functor 'fn' with each line of the file as argument
+ *
+ * \param STRING string type used for the line
+ */
+ template
+ void for_each_line(FN const &fn) const
+ {
+ char const *src = _buffer;
+ char const *curr_line = src;
+ size_t curr_line_len = 0;
+
+ for (size_t n = 0; n < _size; n++) {
+
+ char const c = *src++;
+ bool const end_of_data = (c == 0 || n + 1 == _size);
+ bool const end_of_line = (c == '\n');
+
+ if (!end_of_data && !end_of_line) {
+ curr_line_len++;
+ continue;
+ }
+
+ fn(STRING(Cstring(curr_line, curr_line_len)));
+
+ if (end_of_data)
+ return;
+
+ curr_line = src;
+ curr_line_len = 0;
+ }
+ }
+};
+
+#endif /* _INCLUDE__GEMS__VFS_H_ */
diff --git a/repos/gems/run/depot_query.run b/repos/gems/run/depot_query.run
new file mode 100644
index 0000000000..18ec2be7b4
--- /dev/null
+++ b/repos/gems/run/depot_query.run
@@ -0,0 +1,127 @@
+build { app/depot_query app/depot_deploy }
+
+create_boot_directory
+
+import_from_depot genodelabs/src/[base_src] \
+ genodelabs/src/report_rom \
+ genodelabs/src/fs_rom \
+ genodelabs/src/vfs \
+ genodelabs/src/init
+
+create_tar_from_depot_binaries [run_dir]/genode/depot.tar \
+ genodelabs/pkg/test-fs_report
+
+proc query_pkg {} {
+ return [_versioned_depot_archive_name genodelabs pkg test-fs_report] }
+
+install_config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+build_boot_image { depot_query depot_deploy }
+
+run_genode_until {.*child "test-fs_report" exited with exit value 0.*\n} 30
+
diff --git a/repos/gems/src/app/depot_deploy/main.cc b/repos/gems/src/app/depot_deploy/main.cc
new file mode 100644
index 0000000000..9b60fa9f2b
--- /dev/null
+++ b/repos/gems/src/app/depot_deploy/main.cc
@@ -0,0 +1,164 @@
+/*
+ * \brief Tool for turning a subsystem blueprint into an init configuration
+ * \author Norman Feske
+ * \date 2017-07-07
+ */
+
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+
+namespace Depot_deploy {
+ using namespace Genode;
+ struct Main;
+}
+
+
+struct Depot_deploy::Main
+{
+ Env &_env;
+
+ Attached_rom_dataspace _config { _env, "config" };
+ Attached_rom_dataspace _blueprint { _env, "blueprint" };
+
+ Reporter _init_config_reporter { _env, "config", "init.config" };
+
+ Signal_handler _config_handler {
+ _env.ep(), *this, &Main::_handle_config };
+
+ typedef String<128> Name;
+ typedef String<80> Binary;
+
+ /**
+ * 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();
+
+ Reporter::Xml_generator xml(_init_config_reporter, [&] () {
+
+ 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_sub_node("binary")) {
+ warning(" node for '", name, "' lacks node");
+ return;
+ }
+
+ xml.node("start", [&] () {
+ _gen_start_node(xml, pkg, config.sub_node("common_routes"));
+ });
+ });
+ });
+ }
+
+ Main(Env &env) : _env(env)
+ {
+ _init_config_reporter.enabled(true);
+
+ _config .sigh(_config_handler);
+ _blueprint.sigh(_config_handler);
+
+ _handle_config();
+ }
+};
+
+
+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.sub_node("binary").attribute_value("name", Binary());
+
+ 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", [&] () {
+
+ /*
+ * 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", label);
+ xml.node("parent", [&] () {
+ xml.attribute("label", path);
+ });
+ });
+ });
+
+ /*
+ * Add common routes as defined in our config.
+ */
+ xml.append(common.content_base(), common.content_size());
+ });
+}
+
+
+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
new file mode 100644
index 0000000000..ce426d3220
--- /dev/null
+++ b/repos/gems/src/app/depot_deploy/target.mk
@@ -0,0 +1,3 @@
+TARGET = depot_deploy
+SRC_CC = main.cc
+LIBS += base vfs
diff --git a/repos/gems/src/app/depot_query/main.cc b/repos/gems/src/app/depot_query/main.cc
new file mode 100644
index 0000000000..c43b69cf41
--- /dev/null
+++ b/repos/gems/src/app/depot_query/main.cc
@@ -0,0 +1,301 @@
+/*
+ * \brief Tool for querying subsystem information from a depot
+ * \author Norman Feske
+ * \date 2017-07-04
+ */
+
+/*
+ * Copyright (C) 2017 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.
+ */
+
+/* Genode includes */
+#include
+#include
+#include
+#include
+#include
+
+namespace Depot_query {
+ using namespace Genode;
+ struct Archive;
+ struct Main;
+}
+
+
+struct Depot_query::Archive
+{
+ typedef String<100> Path;
+ typedef String<64> User;
+ typedef String<80> Name;
+
+ enum Type { PKG, RAW, SRC };
+
+ struct Unknown_archive_type : Exception { };
+
+ /**
+ * Return Nth path element
+ *
+ * The first path element corresponds to n == 0.
+ */
+ template
+ static STRING _path_element(Path const &path, unsigned n)
+ {
+ char const *s = path.string();
+
+ /* skip 'n' path elements */
+ for (; n > 0; n--) {
+
+ /* search '/' */
+ while (*s && *s != '/')
+ s++;
+
+ if (*s == 0)
+ return STRING();
+
+ /* skip '/' */
+ s++;
+ }
+
+ /* find '/' marking the end of the path element */
+ unsigned i = 0;
+ while (s[i] != 0 && s[i] != '/')
+ i++;
+
+ return STRING(Cstring(s, i));
+ }
+
+ /**
+ * Return archive user of depot-local path
+ */
+ static User user(Path const &path) { return _path_element(path, 0); }
+
+ /**
+ * Return archive type of depot-local path
+ *
+ * \throw Unknown_archive_type
+ */
+ static Type type(Path const &path)
+ {
+ typedef String<8> Name;
+ Name const name = _path_element(path, 1);
+
+ if (name == "src") return SRC;
+ if (name == "pkg") return PKG;
+ if (name == "raw") return RAW;
+
+ throw Unknown_archive_type();
+ }
+
+ static Name name(Path const &path) { return _path_element(path, 2); }
+};
+
+
+struct Depot_query::Main
+{
+ Env &_env;
+
+ Heap _heap { _env.ram(), _env.rm() };
+
+ Attached_rom_dataspace _config { _env, "config" };
+
+ Root_directory _root { _env, _heap, _config.xml().sub_node("vfs") };
+
+ Signal_handler _config_handler {
+ _env.ep(), *this, &Main::_handle_config };
+
+ Reporter _directory_reporter { _env, "directory" };
+ Reporter _blueprint_reporter { _env, "blueprint" };
+
+ typedef String<64> Rom_label;
+ typedef String<16> Architecture;
+
+ Architecture _architecture;
+
+ Archive::Path _find_rom_in_pkg(Directory::Path const &pkg_path,
+ Rom_label const &rom_label,
+ unsigned const nesting_level);
+
+ void _scan_depot_user_pkg(Archive::User const &user, Directory &dir, Xml_generator &xml);
+ void _query_pkg(Directory::Path const &path, Xml_generator &xml);
+
+ void _handle_config()
+ {
+ _config.update();
+
+ Xml_node config = _config.xml();
+
+ _directory_reporter.enabled(config.has_sub_node("scan"));
+ _blueprint_reporter.enabled(config.has_sub_node("query"));
+
+ _root.apply_config(config.sub_node("vfs"));
+
+ if (!config.has_attribute("arch"))
+ warning("config lacks 'arch' attribute");
+
+ _architecture = config.attribute_value("arch", Architecture());
+
+ if (_directory_reporter.enabled()) {
+
+ Reporter::Xml_generator xml(_directory_reporter, [&] () {
+ config.for_each_sub_node("scan", [&] (Xml_node node) {
+ Archive::User const user = node.attribute_value("user", Archive::User());
+ Directory::Path path("depot/", user, "/pkg");
+ Directory pkg_dir(_root, path);
+ _scan_depot_user_pkg(user, pkg_dir, xml);
+ });
+ });
+ }
+
+ if (_blueprint_reporter.enabled()) {
+
+ Reporter::Xml_generator xml(_blueprint_reporter, [&] () {
+ config.for_each_sub_node("query", [&] (Xml_node node) {
+ _query_pkg(node.attribute_value("pkg", Directory::Path()), xml); });
+ });
+ }
+ }
+
+ Main(Env &env) : _env(env) { _handle_config(); }
+};
+
+
+void Depot_query::Main::_scan_depot_user_pkg(Archive::User const &user,
+ Directory &dir, Xml_generator &xml)
+{
+ dir.for_each_entry([&] (Directory::Entry &entry) {
+
+ if (!dir.file_exists(Directory::Path(entry.name(), "/runtime")))
+ return;
+
+ Archive::Path const path(user, "/pkg/", entry.name());
+
+ xml.node("pkg", [&] () { xml.attribute("path", path); });
+ });
+}
+
+
+Depot_query::Archive::Path
+Depot_query::Main::_find_rom_in_pkg(Directory::Path const &pkg_path,
+ Rom_label const &rom_label,
+ unsigned const nesting_level)
+{
+ if (nesting_level == 0) {
+ error("too deeply nested pkg archives");
+ return Archive::Path();
+ }
+
+ /*
+ * \throw Directory::Nonexistent_directory
+ */
+ Directory depot_dir(_root, Directory::Path("depot"));
+ Directory pkg_dir(depot_dir, pkg_path);
+
+ /*
+ * \throw Directory::Nonexistent_file
+ * \throw File::Truncated_during_read
+ */
+ File_content archives(_heap, pkg_dir, "archives", File_content::Limit{16*1024});
+
+ Archive::Path result;
+
+ archives.for_each_line([&] (Archive::Path const &archive_path) {
+
+ /*
+ * \throw Archive::Unknown_archive_type
+ */
+ switch (Archive::type(archive_path)) {
+ case Archive::SRC:
+ {
+ Archive::Path const
+ rom_path(Archive::user(archive_path), "/bin/",
+ _architecture, "/",
+ Archive::name(archive_path), "/", rom_label);
+
+ if (depot_dir.file_exists(rom_path))
+ result = rom_path;
+ }
+ break;
+
+ case Archive::RAW:
+ log(" ", archive_path, " (raw-data archive)");
+ break;
+
+ case Archive::PKG:
+ // XXX call recursively, adjust 'nesting_level'
+ log(" ", archive_path, " (pkg archive)");
+ break;
+ }
+ });
+ return result;
+}
+
+
+void Depot_query::Main::_query_pkg(Directory::Path const &pkg_path, Xml_generator &xml)
+{
+ Directory pkg_dir(_root, Directory::Path("depot/", pkg_path));
+
+ File_content runtime(_heap, pkg_dir, "runtime", File_content::Limit{16*1024});
+
+ runtime.xml([&] (Xml_node node) {
+
+ xml.node("pkg", [&] () {
+
+ xml.attribute("name", Archive::name(pkg_path));
+ xml.attribute("path", pkg_path);
+
+ Xml_node env_xml = _config.xml().has_sub_node("env")
+ ? _config.xml().sub_node("env") : "";
+
+ node.for_each_sub_node([&] (Xml_node node) {
+
+ /* skip non-rom nodes */
+ if (!node.has_type("rom") && !node.has_type("binary"))
+ return;
+
+ Rom_label const label = node.attribute_value("label", Rom_label());
+
+ /* skip ROM that is provided by the environment */
+ bool provided_by_env = false;
+ env_xml.for_each_sub_node("rom", [&] (Xml_node node) {
+ if (node.attribute_value("label", Rom_label()) == label)
+ provided_by_env = true; });
+
+ if (provided_by_env) {
+ xml.node("rom", [&] () {
+ xml.attribute("label", label);
+ xml.attribute("env", "yes");
+ });
+ return;
+ }
+
+ unsigned const max_nesting_levels = 8;
+ Archive::Path const rom_path =
+ _find_rom_in_pkg(pkg_path, label, max_nesting_levels);
+
+ if (rom_path.valid()) {
+ xml.node("rom", [&] () {
+ xml.attribute("label", label);
+ xml.attribute("path", rom_path);
+ });
+
+ } else {
+
+ xml.node("missing_rom", [&] () {
+ xml.attribute("label", label); });
+ }
+ });
+
+ String<160> comment("\n\n\n");
+ xml.append(comment.string());
+ xml.append(node.addr(), node.size());
+ xml.append("\n");
+ });
+ });
+}
+
+
+void Component::construct(Genode::Env &env) { static Depot_query::Main main(env); }
+
diff --git a/repos/gems/src/app/depot_query/target.mk b/repos/gems/src/app/depot_query/target.mk
new file mode 100644
index 0000000000..d2129486f8
--- /dev/null
+++ b/repos/gems/src/app/depot_query/target.mk
@@ -0,0 +1,3 @@
+TARGET = depot_query
+SRC_CC = main.cc
+LIBS += base vfs
diff --git a/repos/os/recipes/pkg/test-fs_report/runtime b/repos/os/recipes/pkg/test-fs_report/runtime
index 1ae13f8032..9da707c1c7 100644
--- a/repos/os/recipes/pkg/test-fs_report/runtime
+++ b/repos/os/recipes/pkg/test-fs_report/runtime
@@ -4,11 +4,11 @@
-
-
-
-
-
+
+
+
+
+
@@ -16,7 +16,7 @@
-