diff --git a/run/chroot.run b/run/chroot.run
new file mode 100644
index 0000000..cf56009
--- /dev/null
+++ b/run/chroot.run
@@ -0,0 +1,129 @@
+#
+# \brief Chroot test
+# \author Emery Hemingway
+# \date 2016-12-03
+#
+
+#
+# Build
+#
+
+build { core init server/vfs server/chroot test/libc }
+
+create_boot_directory
+
+#
+# Generate config
+#
+
+set config {
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
+
+install_config $config
+
+#
+# Boot modules
+#
+
+build_boot_image {
+ core init vfs chroot
+ ld.lib.so libc.lib.so libm.lib.so
+ test-libc
+}
+
+#
+# Execute test case
+#
+
+append qemu_args " -nographic -m 64 "
+run_genode_until {child "test-libc-3" exited with exit value 0} 60
+
+# vi: set ft=tcl :
diff --git a/src/server/chroot/component.cc b/src/server/chroot/component.cc
index d64e826..5d6f3d5 100644
--- a/src/server/chroot/component.cc
+++ b/src/server/chroot/component.cc
@@ -16,100 +16,132 @@
#include
#include
#include
-#include
#include
#include
-#include
+#include
#include
#include
#include
-using namespace Genode;
+namespace Chroot {
+ using namespace Genode;
+ struct Main;
+ template
+ static void path_from_label(Path &path, char const *label)
+ {
+ char tmp[MAX_LEN];
+ size_t len = strlen(label);
-template
-static void path_from_label(Path &path, char const *label)
-{
- char tmp[MAX_LEN];
- size_t len = strlen(label);
+ size_t i = 0;
+ for (size_t j = 1; j < len; ++j) {
+ if (!strcmp(" -> ", label+j, 4)) {
+ path.append("/");
- size_t i = 0;
- for (size_t j = 1; j < len; ++j) {
- if (!strcmp(" -> ", label+j, 4)) {
- path.append("/");
+ strncpy(tmp, label+i, (j-i)+1);
+ /* rewrite any directory seperators */
+ for (size_t k = 0; k < MAX_LEN; ++k)
+ if (tmp[k] == '/')
+ tmp[k] = '_';
+ path.append(tmp);
- strncpy(tmp, label+i, (j-i)+1);
- /* rewrite any directory seperators */
- for (size_t k = 0; k < MAX_LEN; ++k)
- if (tmp[k] == '/')
- tmp[k] = '_';
- path.append(tmp);
-
- j += 4;
- i = j;
+ j += 4;
+ i = j;
+ }
}
+ path.append("/");
+ strncpy(tmp, label+i, MAX_LEN);
+ /* rewrite any directory seperators */
+ for (size_t k = 0; k < MAX_LEN; ++k)
+ if (tmp[k] == '/')
+ tmp[k] = '_';
+ path.append(tmp);
}
- path.append("/");
- strncpy(tmp, label+i, MAX_LEN);
- /* rewrite any directory seperators */
- for (size_t k = 0; k < MAX_LEN; ++k)
- if (tmp[k] == '/')
- tmp[k] = '_';
- path.append(tmp);
}
-struct Proxy : Rpc_object>
+
+struct Chroot::Main
{
- Genode::Attached_rom_dataspace _config_rom;
- Parent_service _parent_service;
- Heap _heap;
- Allocator_avl _fs_tx_block_alloc { &_heap };
- File_system::Connection _fs { _fs_tx_block_alloc, 1024 };
+ enum { PATH_MAX_LEN = 128 };
+ typedef Genode::Path Path;
+
+ struct Session : Parent::Server
+ {
+ Parent::Client parent_client;
+
+ Id_space::Element client_id;
+ Id_space::Element server_id;
+
+ Session(Id_space &client_space,
+ Id_space &server_space,
+ Parent::Server::Id server_id)
+ :
+ client_id(parent_client, client_space),
+ server_id(*this, server_space, server_id) { }
+ };
+
+ Genode::Env &env;
+
+ Id_space server_id_space;
+
+ Heap heap { env.ram(), env.rm() };
+
+ Allocator_avl fs_tx_block_alloc { &heap };
+ File_system::Connection fs { fs_tx_block_alloc, 1 };
+
+ Attached_rom_dataspace session_requests { env, "session_requests" };
+
+ Attached_rom_dataspace config_rom { env, "config" };
+
+ void handle_session_request(Xml_node request);
+
+ void handle_session_requests()
+ {
+ if (config_sig_rec.pending()) {
+ do { config_sig_rec.pending_signal(); }
+ while (config_sig_rec.pending());
+ config_rom.update();
+ }
+
+ session_requests.update();
+
+ Xml_node const requests = session_requests.xml();
+
+ requests.for_each_sub_node([&] (Xml_node request) {
+ handle_session_request(request);
+ });
+ }
+
+ Signal_handler session_request_handler {
+ env.ep(), *this, &Main::handle_session_requests };
+
+ Signal_context config_sig_ctx;
+ Signal_receiver config_sig_rec;
/**
* Constructor
*/
- Proxy(Genode::Env &env)
- :
- _config_rom(env, "config"),
- _parent_service("File_system"),
- _heap(env.ram(), env.rm())
+ Main(Genode::Env &env) : env(env)
{
- env.parent().announce(env.ep().rpc_ep().manage(this));
+ config_rom.sigh(config_sig_rec.manage(&config_sig_ctx));
+ session_requests.sigh(session_request_handler);
}
- Session_capability chroot(char const *args, char const *path, Affinity const &affinity)
+ ~Main() {
+ config_sig_rec.dissolve(&config_sig_ctx); }
+
+ Session_capability request_session(Parent::Client::Id const &id,
+ Session_state::Args const &args)
{
- enum { ARGS_MAX_LEN = 256 };
- char new_args[ARGS_MAX_LEN];
+ char tmp[PATH_MAX_LEN];
+ Path root_path;
- strncpy(new_args, args, ARGS_MAX_LEN);
- Arg_string::set_arg_string(new_args, ARGS_MAX_LEN, "root", path);
-
- try { return _parent_service.session(new_args, affinity); }
- catch (Service::Invalid_args) { throw Root::Invalid_args(); }
- catch (Service::Quota_exceeded) { throw Root::Quota_exceeded(); }
- catch (...) { }
- throw Root::Unavailable();
- }
-
-
- /********************
- ** Root interface **
- ********************/
-
- Session_capability session(Root::Session_args const &session_args,
- Affinity const &affinity)
- {
- enum { MAX_LEN = 128 };
- char tmp[MAX_LEN];
- Path root_path;
-
- Session_label label = label_from_args(session_args.string());
+ Session_label label = label_from_args(args.string());
char const *label_str = label.string();
+ /* if policy specifies a merge, use a truncated label */
try {
- Session_policy policy(label, _config_rom.xml());
+ Session_policy policy(label, config_rom.xml());
if (policy.has_attribute("label_prefix")
&& policy.attribute_value("merge", false))
@@ -127,48 +159,111 @@ struct Proxy : Rpc_object>
}
} catch (Session_policy::No_policy_defined) { }
+
+ /* create a new path from the label */
path_from_label(root_path, label_str);
- Arg_string::find_arg(session_args.string(), "root").string(
+ /* extract and append the orginal root */
+ Arg_string::find_arg(args.string(), "root").string(
tmp, sizeof(tmp), "/");
root_path.append_element(tmp);
root_path.remove_trailing('/');
- char const *args = session_args.string();
char const *new_root = root_path.base();
using namespace File_system;
- Dir_handle handle;
- char const *errstr;
+
+ /* create the new root directory if it is missing */
+ try { fs.close(ensure_dir(fs, new_root)); }
+ catch (Node_already_exists) { }
+ catch (Permission_denied) {
+ Genode::error(new_root,": permission denied"); throw; }
+ catch (Name_too_long) {
+ Genode::error(new_root,": new root too long"); throw; }
+ catch (No_space) {
+ Genode::error(new_root,": no space"); throw; }
+ catch (...) {
+ Genode::error(new_root,": unknown error"); throw; }
+
+ /* rewrite the root session argument */
+ enum { ARGS_MAX_LEN = 256 };
+ char new_args[ARGS_MAX_LEN];
+
+ strncpy(new_args, args.string(), ARGS_MAX_LEN);
+ Arg_string::set_arg_string(new_args, ARGS_MAX_LEN, "root", new_root);
+
+ Affinity affinity;
+ return env.session("File_system", id, new_args, affinity);
+ }
+};
+
+
+void Chroot::Main::handle_session_request(Xml_node request)
+{
+ if (!request.has_attribute("id"))
+ return;
+
+ Parent::Server::Id const server_id { request.attribute_value("id", 0UL) };
+
+ if (request.has_type("create")) {
+
+ if (!request.has_sub_node("args"))
+ return;
+
+ typedef Session_state::Args Args;
+ Args const args = request.sub_node("args").decoded_content();
+
+ Session *session = nullptr;
try {
- _fs.close(ensure_dir(_fs, new_root));
- return chroot(args, new_root, affinity);
+ session = new (heap)
+ Session(env.id_space(), server_id_space, server_id);
+
+ Session_capability cap = request_session(session->client_id.id(), args);
+
+ env.parent().deliver_session_cap(server_id, cap);
}
- catch (Node_already_exists) { return chroot(args, new_root, affinity); }
-
- catch (Permission_denied) { errstr = "permission denied"; }
- catch (Name_too_long) { errstr = "new root too long"; }
- catch (No_space) { errstr = "no space"; }
- catch (...) { errstr = "unknown error"; }
-
- Genode::error(new_root, ": ", errstr);
- throw Root::Unavailable();
+ catch (...) {
+ if (session)
+ destroy(heap, session);
+ env.parent().session_response(server_id, Parent::INVALID_ARGS);
+ }
}
- void upgrade(Session_capability cap,
- Root::Upgrade_args const &args) override {
- _parent_service.upgrade(cap, args.string()); }
+ if (request.has_type("upgrade")) {
- void close(Session_capability cap) override {
- _parent_service.close(cap); }
-};
+ server_id_space.apply(server_id, [&] (Session &session) {
+
+ size_t ram_quota = request.attribute_value("ram_quota", 0UL);
+
+ char buf[64];
+ snprintf(buf, sizeof(buf), "ram_quota=%ld", ram_quota);
+
+ // XXX handle Root::Invalid_args
+ env.upgrade(session.client_id.id(), buf);
+ env.parent().session_response(server_id, Parent::SESSION_OK);
+ });
+ }
+
+ if (request.has_type("close")) {
+ server_id_space.apply(server_id, [&] (Session &session) {
+ env.close(session.client_id.id());
+ destroy(heap, &session);
+ env.parent().session_response(server_id, Parent::SESSION_CLOSED);
+ });
+ }
+}
/***************
** Component **
***************/
-Genode::size_t Component::stack_size() { return 2*1024*sizeof(Genode::addr_t); }
+Genode::size_t Component::stack_size() {
+ return 2*1024*sizeof(Genode::addr_t); }
-void Component::construct(Genode::Env &env) { static Proxy inst(env); }
+void Component::construct(Genode::Env &env)
+{
+ static Chroot::Main inst(env);
+ env.parent().announce("File_system");
+}