xml_term_edit: use libc for file I/O

Ref #91
This commit is contained in:
Emery Hemingway
2017-10-26 11:34:26 -05:00
parent dbd6962ebf
commit f79aa89f7e
3 changed files with 61 additions and 128 deletions

View File

@@ -105,7 +105,7 @@ append config {
<resource name="RAM" quantum="2M"/>
<provides><service name="Terminal"/></provides>
<config>
<keyboard layout="us"/>
<keyboard layout="none"/>
</config>
<route>
<any-service> <parent/> <any-child/> </any-service>

View File

@@ -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);
});
}

View File

@@ -1,5 +1,5 @@
TARGET = xml_term_edit
SRC_CC = component.cc
LIBS = base vfs
LIBS = base libc
INC_DIR += $(PRG_DIR) $(call select_from_repositories,src/app/cli_monitor)