|
|
|
|
@@ -13,17 +13,22 @@
|
|
|
|
|
|
|
|
|
|
/* Genode includes */
|
|
|
|
|
#include <os/reporter.h>
|
|
|
|
|
#include <vfs/file_system_factory.h>
|
|
|
|
|
#include <vfs/dir_file_system.h>
|
|
|
|
|
#include <terminal_session/connection.h>
|
|
|
|
|
#include <base/attached_rom_dataspace.h>
|
|
|
|
|
#include <base/heap.h>
|
|
|
|
|
#include <base/component.h>
|
|
|
|
|
#include <libc/component.h>
|
|
|
|
|
|
|
|
|
|
/* Cli_monitor includes */
|
|
|
|
|
#include <command_line.h>
|
|
|
|
|
#include <line_editor.h>
|
|
|
|
|
|
|
|
|
|
/* Libc includes */
|
|
|
|
|
#include <dirent.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <fcntl.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
|
|
namespace Xml_term_edit {
|
|
|
|
|
using namespace Genode;
|
|
|
|
|
@@ -36,94 +41,46 @@ namespace Xml_term_edit {
|
|
|
|
|
struct Main;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Genode::Env *_env;
|
|
|
|
|
|
|
|
|
|
struct Xml_term_edit::Command : Cli_monitor::Command
|
|
|
|
|
{
|
|
|
|
|
Vfs::Dir_file_system &vfs;
|
|
|
|
|
Genode::Allocator &alloc;
|
|
|
|
|
Reporter &report;
|
|
|
|
|
Vfs::Vfs_handle *root_handle = nullptr;
|
|
|
|
|
|
|
|
|
|
Command(char const *name,
|
|
|
|
|
char const *desc,
|
|
|
|
|
Command_registry &cmds,
|
|
|
|
|
Vfs::Dir_file_system &vfs,
|
|
|
|
|
Genode::Allocator &alloc,
|
|
|
|
|
Reporter &report)
|
|
|
|
|
:
|
|
|
|
|
Cli_monitor::Command(name, desc),
|
|
|
|
|
vfs(vfs), alloc(alloc), report(report)
|
|
|
|
|
alloc(alloc), report(report)
|
|
|
|
|
{
|
|
|
|
|
auto r = vfs.open(
|
|
|
|
|
"/", Vfs::Directory_service::OPEN_MODE_RDONLY, &root_handle, alloc);
|
|
|
|
|
if (r != Vfs::Directory_service::Open_result::OPEN_OK) {
|
|
|
|
|
Genode::error("failed to open VFS root directory");
|
|
|
|
|
throw r;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cmds.insert(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* TODO: this is too slow, cache it
|
|
|
|
|
*/
|
|
|
|
|
void _for_each_argument(Argument_fn const &fn) const override
|
|
|
|
|
{
|
|
|
|
|
typedef Vfs::File_io_service::Read_result Result;
|
|
|
|
|
DIR *dirp = opendir("/");
|
|
|
|
|
if (dirp == NULL) {
|
|
|
|
|
Genode::error("failed to read root directory");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum { DIRENT_COUNT = 4096 / sizeof(Vfs::Directory_service::Dirent) };
|
|
|
|
|
Vfs::Directory_service::Dirent dirents[DIRENT_COUNT];
|
|
|
|
|
memset(dirents, 0x00, sizeof(dirents));
|
|
|
|
|
|
|
|
|
|
root_handle->seek(0);
|
|
|
|
|
|
|
|
|
|
for (;;) {
|
|
|
|
|
while (!vfs.queue_read(root_handle, sizeof(dirents))) {
|
|
|
|
|
_env->ep().wait_and_dispatch_one_io_signal();
|
|
|
|
|
}
|
|
|
|
|
Vfs::file_size read_count = 0;
|
|
|
|
|
Result r;
|
|
|
|
|
for (;;) {
|
|
|
|
|
r = vfs.complete_read(
|
|
|
|
|
root_handle, (char*)&dirents, sizeof(dirents), read_count);
|
|
|
|
|
if (r == Result::READ_QUEUED) {
|
|
|
|
|
_env->ep().wait_and_dispatch_one_io_signal();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r != Result::READ_OK) {
|
|
|
|
|
Genode::error("failed to read subsystems");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (read_count == 0) return;
|
|
|
|
|
root_handle->advance_seek(read_count);
|
|
|
|
|
read_count = read_count / sizeof(Vfs::Directory_service::Dirent);
|
|
|
|
|
|
|
|
|
|
for (unsigned i = 0; i < read_count; i++) {
|
|
|
|
|
Vfs::Directory_service::Dirent const &e = dirents[i];
|
|
|
|
|
|
|
|
|
|
switch (e.type) {
|
|
|
|
|
case Vfs::Directory_service::DIRENT_TYPE_FILE:
|
|
|
|
|
/* check if the VFS returned junk */
|
|
|
|
|
if (e.name[0] != '\0')
|
|
|
|
|
fn(Argument(e.name, ""));
|
|
|
|
|
break;
|
|
|
|
|
case Vfs::Directory_service::DIRENT_TYPE_END:
|
|
|
|
|
return;
|
|
|
|
|
default:
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
dirent *dp;
|
|
|
|
|
while ((dp = readdir(dirp)) != NULL) {
|
|
|
|
|
if (dp->d_type == DT_REG) {
|
|
|
|
|
fn(Argument(dp->d_name, ""));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
closedir(dirp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void insert_file_content(Command_line &cmd, Xml_generator gen)
|
|
|
|
|
{
|
|
|
|
|
using namespace Vfs;
|
|
|
|
|
|
|
|
|
|
Path<128> path;
|
|
|
|
|
Vfs_handle *handle;
|
|
|
|
|
{
|
|
|
|
|
char name[128] = { '\0' };
|
|
|
|
|
if (cmd.argument(0, name, sizeof(name)) == false) {
|
|
|
|
|
@@ -133,41 +90,24 @@ struct Xml_term_edit::Command : Cli_monitor::Command
|
|
|
|
|
path.import(name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Directory_service::Stat sb;
|
|
|
|
|
vfs.stat(path.base(), sb);
|
|
|
|
|
|
|
|
|
|
/* XXX: error handling */
|
|
|
|
|
if (!sb.size)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
typedef Directory_service::Open_result Open_result;
|
|
|
|
|
Open_result res = vfs.open(
|
|
|
|
|
path.base(),
|
|
|
|
|
Directory_service::OPEN_MODE_RDONLY,
|
|
|
|
|
&handle,
|
|
|
|
|
alloc);
|
|
|
|
|
switch (res) {
|
|
|
|
|
case Open_result::OPEN_OK:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
error("failed to open '", path, "'");
|
|
|
|
|
/* XXX: log and write error info to the terminal */
|
|
|
|
|
int fd = open(path.base(), O_RDONLY);
|
|
|
|
|
if (fd == -1) {
|
|
|
|
|
Genode::error("failed to open '", path, "'");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
Vfs_handle::Guard guard(handle);
|
|
|
|
|
|
|
|
|
|
char buf[1024];
|
|
|
|
|
file_size offset = 0;
|
|
|
|
|
while (offset < sb.size) {
|
|
|
|
|
file_size n = 0;
|
|
|
|
|
file_size count = min(sizeof(buf), sb.size-offset);
|
|
|
|
|
handle->fs().complete_read(handle, buf, count, n);
|
|
|
|
|
if (!n)
|
|
|
|
|
return;
|
|
|
|
|
gen.append(buf, n);
|
|
|
|
|
offset += n;
|
|
|
|
|
handle->advance_seek(n);
|
|
|
|
|
for (;;) {
|
|
|
|
|
auto n = read(fd, buf, sizeof(buf));
|
|
|
|
|
if (n > 0) {
|
|
|
|
|
gen.append(buf, n);
|
|
|
|
|
} else {
|
|
|
|
|
if (n < 0)
|
|
|
|
|
Genode::error("failed to read '", path, "'");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
close(fd);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
@@ -175,10 +115,9 @@ struct Xml_term_edit::Command : Cli_monitor::Command
|
|
|
|
|
struct Xml_term_edit::Add_command : Xml_term_edit::Command
|
|
|
|
|
{
|
|
|
|
|
Add_command(Command_registry &cmds,
|
|
|
|
|
Vfs::Dir_file_system &vfs,
|
|
|
|
|
Genode::Allocator &alloc,
|
|
|
|
|
Reporter &report)
|
|
|
|
|
: Command("add", "add a new subsystem to init", cmds, vfs, alloc, report)
|
|
|
|
|
: Command("add", "add a new subsystem to init", cmds, alloc, report)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
void execute(Command_line &cmd, Terminal::Session &terminal) override
|
|
|
|
|
@@ -193,10 +132,9 @@ struct Xml_term_edit::Add_command : Xml_term_edit::Command
|
|
|
|
|
struct Xml_term_edit::Del_command : Xml_term_edit::Command
|
|
|
|
|
{
|
|
|
|
|
Del_command(Command_registry &cmds,
|
|
|
|
|
Vfs::Dir_file_system &vfs,
|
|
|
|
|
Genode::Allocator &alloc,
|
|
|
|
|
Reporter &report)
|
|
|
|
|
: Command("del", "delete a subsystem from init", cmds, vfs, alloc, report)
|
|
|
|
|
: Command("del", "delete a subsystem from init", cmds, alloc, report)
|
|
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
void execute(Command_line &cmd, Terminal::Session &terminal) override
|
|
|
|
|
@@ -237,18 +175,8 @@ struct Xml_term_edit::Main
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
struct Io_response_handler : Vfs::Io_response_handler
|
|
|
|
|
{
|
|
|
|
|
void handle_io_response(Vfs::Vfs_handle::Context *) override { }
|
|
|
|
|
} io_response_handler;
|
|
|
|
|
|
|
|
|
|
Heap heap { env.ram(), env.rm() };
|
|
|
|
|
|
|
|
|
|
Vfs::Global_file_system_factory vfs_factory { heap };
|
|
|
|
|
|
|
|
|
|
Vfs::Dir_file_system vfs_root {
|
|
|
|
|
env, heap, vfs_config(), io_response_handler, vfs_factory };
|
|
|
|
|
|
|
|
|
|
Terminal::Connection term { env, "edit" };
|
|
|
|
|
|
|
|
|
|
Reporter reporter { env, "xml_editor", "edit", env.ram().avail_ram().value / 2 };
|
|
|
|
|
@@ -265,8 +193,8 @@ struct Xml_term_edit::Main
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Add_command add_command { cmds, vfs_root, heap, reporter };
|
|
|
|
|
Del_command del_command { cmds, vfs_root, heap, reporter };
|
|
|
|
|
Add_command add_command { cmds, heap, reporter };
|
|
|
|
|
Del_command del_command { cmds, heap, reporter };
|
|
|
|
|
Exit_command exit_command { cmds, env.parent() };
|
|
|
|
|
|
|
|
|
|
enum { COMMAND_MAX_LEN = 1024 };
|
|
|
|
|
@@ -290,24 +218,29 @@ struct Xml_term_edit::Main
|
|
|
|
|
|
|
|
|
|
void Xml_term_edit::Main::handle_term()
|
|
|
|
|
{
|
|
|
|
|
while (term.avail() && !editor.completed()) {
|
|
|
|
|
char c = 0;
|
|
|
|
|
term.read(&c, 1);
|
|
|
|
|
editor.submit_input(c);
|
|
|
|
|
}
|
|
|
|
|
Libc::with_libc([&] () {
|
|
|
|
|
|
|
|
|
|
if (editor.completed()) {
|
|
|
|
|
auto *cmd = lookup_command(cmd_buf);
|
|
|
|
|
if (cmd) {
|
|
|
|
|
Cli_monitor::Command_line cmd_line(cmd_buf, *cmd);
|
|
|
|
|
cmd->execute(cmd_line, term);
|
|
|
|
|
while (term.avail() && !editor.completed()) {
|
|
|
|
|
char c = 0;
|
|
|
|
|
term.read(&c, 1);
|
|
|
|
|
editor.submit_input(c);
|
|
|
|
|
}
|
|
|
|
|
editor.reset();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (editor.completed()) {
|
|
|
|
|
|
|
|
|
|
auto *cmd = lookup_command(cmd_buf);
|
|
|
|
|
if (cmd) {
|
|
|
|
|
Cli_monitor::Command_line cmd_line(cmd_buf, *cmd);
|
|
|
|
|
cmd->execute(cmd_line, term);
|
|
|
|
|
}
|
|
|
|
|
editor.reset();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void Component::construct(Genode::Env &env)
|
|
|
|
|
void Libc::Component::construct(Libc::Env &env)
|
|
|
|
|
{
|
|
|
|
|
_env = &env;
|
|
|
|
|
static Xml_term_edit::Main inst(env);
|
|
|
|
|
Libc::with_libc([&] () {
|
|
|
|
|
static Xml_term_edit::Main inst(env);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|