[6s] Allow 6s to know about filesystems

Added a j6_proto_vfs_tag/_get_tag pair of messages to the VFS protocol
to allow filesystems to label themselves, and gave 6s the concept of
current fs and current working directory.
This commit is contained in:
Justin C. Miller
2024-04-30 22:23:04 -07:00
parent 29332cbd45
commit eb62588b79
10 changed files with 195 additions and 43 deletions

View File

@@ -8,4 +8,6 @@ enum j6_proto_vfs_tag
{ {
j6_proto_vfs_load = j6_proto_base_first_proto_id, j6_proto_vfs_load = j6_proto_base_first_proto_id,
j6_proto_vfs_file, j6_proto_vfs_file,
j6_proto_vfs_get_tag,
j6_proto_vfs_tag,
}; };

View File

@@ -13,7 +13,13 @@ class API client
public: public:
/// Constructor. /// Constructor.
/// \arg vfs_mb Handle to the VFS service's mailbox /// \arg vfs_mb Handle to the VFS service's mailbox
client(j6_handle_t vfs_mb); client(j6_handle_t vfs_mb = 0);
/// Copy constructor
client(const client& c);
/// Check if this client's handle is valid
inline bool valid() const { return m_service != j6_handle_invalid; }
/// Load a file into a VMA /// Load a file into a VMA
/// \arg path Path of the file to load /// \arg path Path of the file to load
@@ -21,6 +27,11 @@ public:
/// \arg size [out] Size of the file /// \arg size [out] Size of the file
j6_status_t load_file(char *path, j6_handle_t &vma, size_t &size); j6_status_t load_file(char *path, j6_handle_t &vma, size_t &size);
/// Get fs tag
/// \arg tag [out] The filesystem's tag
/// \arg size [inout] Size of the input buffer, length of the returned string
j6_status_t get_tag(char *tag, size_t &len);
private: private:
j6_handle_t m_service; j6_handle_t m_service;
}; };

View File

@@ -1,3 +1,4 @@
#include "j6/types.h"
#include <j6/errors.h> #include <j6/errors.h>
#include <j6/protocols/vfs.hh> #include <j6/protocols/vfs.hh>
#include <j6/syscalls.h> #include <j6/syscalls.h>
@@ -12,6 +13,11 @@ client::client(j6_handle_t vfs_mb) :
{ {
} }
client::client(const client& c) :
m_service {c.m_service}
{
}
inline size_t simple_strlen(const char *s) { size_t n = 0; while (s && *s) s++, n++; return n; } inline size_t simple_strlen(const char *s) { size_t n = 0; while (s && *s) s++, n++; return n; }
j6_status_t j6_status_t
@@ -61,5 +67,31 @@ client::load_file(char *path, j6_handle_t &vma, size_t &size)
} }
j6_status_t
client::get_tag(char *tag, size_t &len)
{
if (len < sizeof(j6_status_t))
return j6_err_insufficient;
uint64_t message_tag = j6_proto_vfs_get_tag;
size_t handle_count = 0;
size_t in_len = 0;
j6_status_t s = j6_mailbox_call(m_service, &message_tag,
tag, &in_len, len, nullptr, &handle_count, 0);
if (s != j6_status_ok)
return s;
if (message_tag == j6_proto_base_status)
return *reinterpret_cast<j6_status_t*>(tag); // contains a status
if (message_tag != j6_proto_vfs_tag)
return j6_err_unexpected;
len = in_len;
return j6_status_ok; // data is now in `tag` and `len`
}
} // namespace j6::proto::vfs } // namespace j6::proto::vfs
#endif // __j6kernel #endif // __j6kernel

View File

@@ -7,4 +7,5 @@ module("6s",
sources = [ sources = [
"commands.cpp", "commands.cpp",
"main.cpp", "main.cpp",
"shell.cpp",
]) ])

View File

@@ -1,23 +1,45 @@
#include <edit/line.h> #include <edit/line.h>
#include <util/format.h> #include <util/format.h>
#include "commands.h" #include "commands.h"
#include "shell.h"
static void static void
help(edit::source &s) fslist(shell &s)
{ {
for (unsigned i = 0; i < g_builtins_count; ++i) {
char line[100]; char line[100];
util::counted<char> output { line, sizeof(line) }; util::counted<char> output { line, sizeof(line) };
builtin &cmd = g_builtins[i]; for (auto &f : s.filesystems()) {
size_t len = util::format(output, "%s\r\n", f.tag);
s.write(line, len);
}
}
static void
help(shell &s)
{
char line[100];
util::counted<char> output { line, sizeof(line) };
for (unsigned i = 0; i < g_builtins_count; ++i) {
builtin &cmd = g_builtins[i];
size_t len = util::format(output, "%20s - %s\r\n", cmd.name(), cmd.description()); size_t len = util::format(output, "%20s - %s\r\n", cmd.name(), cmd.description());
s.write(line, len); s.write(line, len);
} }
} }
static void static void
version(edit::source &s) pwd(shell &s)
{
char line[100];
util::counted<char> output { line, sizeof(line) };
size_t len = util::format(output, "%s:%s\r\n", s.cfs(), s.cwd());
s.write(line, len);
}
static void
version(shell &s)
{ {
static const char *gv = GIT_VERSION; static const char *gv = GIT_VERSION;
@@ -29,7 +51,9 @@ version(edit::source &s)
} }
builtin g_builtins[] = { builtin g_builtins[] = {
{ "help", "list availble commands", help }, { "fslist", "list available filesystems", fslist },
{ "help", "list available commands", help },
{ "pwd", "print current working directory", pwd },
{ "version", "print current jsix version", version }, { "version", "print current jsix version", version },
}; };
size_t g_builtins_count = sizeof(g_builtins) / sizeof(g_builtins[0]); size_t g_builtins_count = sizeof(g_builtins) / sizeof(g_builtins[0]);

View File

@@ -2,15 +2,12 @@
#include <stddef.h> #include <stddef.h>
namespace edit { struct shell;
class source;
}
class builtin class builtin
{ {
public: public:
using runf = void (*)(edit::source &); using runf = void (*)(shell &);
builtin(const char *name, const char *desc, runf func) : builtin(const char *name, const char *desc, runf func) :
m_name {name}, m_desc {desc}, m_func {func} {} m_name {name}, m_desc {desc}, m_func {func} {}
@@ -18,7 +15,7 @@ public:
const char * name() const { return m_name; } const char * name() const { return m_name; }
const char * description() const { return m_desc; } const char * description() const { return m_desc; }
void run(edit::source &s) { m_func(s); } void run(shell &s) { m_func(s); }
private: private:
const char *m_name; const char *m_name;

View File

@@ -11,13 +11,13 @@
#include <j6/types.h> #include <j6/types.h>
#include <edit/line.h> #include <edit/line.h>
#include "commands.h" #include "shell.h"
extern "C" { extern "C" {
int main(int, const char **); int main(int, const char **);
} }
j6_handle_t g_handle_sys = j6_handle_invalid; //j6_handle_t g_handle_sys = j6_handle_invalid;
const char prompt[] = "\x1b[1;32mj6> \x1b[0m"; const char prompt[] = "\x1b[1;32mj6> \x1b[0m";
static constexpr size_t prompt_len = sizeof(prompt) - 1; static constexpr size_t prompt_len = sizeof(prompt) - 1;
@@ -31,7 +31,6 @@ const char greeting[] = "\x1b[2J\x1b[H\x1b[1;30m\
static constexpr size_t greeting_len = sizeof(greeting) - 1; static constexpr size_t greeting_len = sizeof(greeting) - 1;
void handle_command(edit::source &s, const char *command, size_t len);
class channel_source : class channel_source :
public edit::source public edit::source
@@ -47,9 +46,13 @@ public:
void write(char const *data, size_t len) override { void write(char const *data, size_t len) override {
uint8_t *outp; uint8_t *outp;
m_chan.reserve(len, &outp); while (len) {
memcpy(outp, data, len); size_t size = m_chan.reserve(len, &outp);
m_chan.commit(len); size_t n = len < size ? len : size;
memcpy(outp, data, n);
m_chan.commit(n);
len -= n;
}
} }
private: private:
@@ -63,14 +66,20 @@ main(int argc, const char **argv)
j6_handle_t event = j6_handle_invalid; j6_handle_t event = j6_handle_invalid;
j6_status_t result = j6_status_ok; j6_status_t result = j6_status_ok;
/*
g_handle_sys = j6_find_init_handle(0); g_handle_sys = j6_find_init_handle(0);
if (g_handle_sys == j6_handle_invalid) if (g_handle_sys == j6_handle_invalid)
return 1; return 1;
*/
j6_handle_t slp = j6_find_init_handle(j6::proto::sl::id); j6_handle_t slp = j6_find_init_handle(j6::proto::sl::id);
if (slp == j6_handle_invalid) if (slp == j6_handle_invalid)
return 3; return 3;
j6_handle_t vfs = j6_find_init_handle(j6::proto::vfs::id);
if (vfs == j6_handle_invalid)
return 4;
uint64_t proto_id = "jsix.protocol.stream.ouput"_id; uint64_t proto_id = "jsix.protocol.stream.ouput"_id;
j6::proto::sl::client slp_client {slp}; j6::proto::sl::client slp_client {slp};
@@ -95,6 +104,9 @@ main(int argc, const char **argv)
channel_source source {*cout}; channel_source source {*cout};
edit::line editor {source}; edit::line editor {source};
shell sh { source };
sh.add_filesystem(vfs);
static constexpr size_t bufsize = 256; static constexpr size_t bufsize = 256;
char buffer [bufsize]; char buffer [bufsize];
@@ -102,25 +114,6 @@ main(int argc, const char **argv)
while (true) { while (true) {
size_t len = editor.read(buffer, bufsize, prompt, prompt_len); size_t len = editor.read(buffer, bufsize, prompt, prompt_len);
handle_command(source, buffer, len); sh.handle_command(buffer, len);
} }
} }
void
handle_command(edit::source &s, const char *command, size_t len)
{
j6::syslog(j6::logs::app, j6::log_level::info, "Command: %s", command);
if (len == 0)
return;
for (unsigned i = 0; i < g_builtins_count; ++i) {
builtin &cmd = g_builtins[i];
if (strncmp(command, cmd.name(), len) == 0) {
cmd.run(s);
return;
}
}
static const char unknown[] = "\x1b[1;33mUnknown command.\x1b[0m\r\n";
s.write(unknown, sizeof(unknown)-1);
}

43
src/user/6s/shell.cpp Normal file
View File

@@ -0,0 +1,43 @@
#include <string.h>
#include <j6/errors.h>
#include <j6/syslog.hh>
#include "commands.h"
#include "shell.h"
void
shell::add_filesystem(j6_handle_t mb)
{
char tag_buf [100];
size_t size = sizeof(tag_buf);
j6::proto::vfs::client c {mb};
j6_status_t s = c.get_tag(tag_buf, size);
if (s != j6_status_ok)
return;
char *name = new char [size + 1];
memcpy(name, tag_buf, size);
name[size] = 0;
m_fs.push_back({name, c});
if (!m_cfs)
m_cfs = name;
}
void
shell::handle_command(const char *command, size_t len)
{
j6::syslog(j6::logs::app, j6::log_level::info, "Command: %s", command);
if (len == 0)
return;
for (unsigned i = 0; i < g_builtins_count; ++i) {
builtin &cmd = g_builtins[i];
if (strncmp(command, cmd.name(), len) == 0) {
cmd.run(*this);
return;
}
}
static const char unknown[] = "\x1b[1;33mUnknown command.\x1b[0m\r\n";
write(unknown, sizeof(unknown)-1);
}

38
src/user/6s/shell.h Normal file
View File

@@ -0,0 +1,38 @@
#pragma once
#include <vector>
#include <j6/protocols/vfs.hh>
#include <edit/line.h>
/// Shell state
class shell
{
public:
struct fs {
const char *tag;
j6::proto::vfs::client client;
};
using fs_list = std::vector<fs>;
shell(edit::source &source) : m_source {source}, m_cwd {"/"}, m_cfs {nullptr} {}
const char * cwd() const { return m_cwd; }
const char * cfs() const { return m_cfs; }
// Transparently use source read/write functions
inline void consume(size_t len) { m_source.consume(len); }
inline void write(char const *data, size_t len) { m_source.write(data, len); }
inline size_t read(char const **data) { return m_source.read(data); }
void add_filesystem(j6_handle_t mb);
inline const fs_list & filesystems() const { return m_fs; }
void handle_command(const char *command, size_t len);
private:
edit::source &m_source;
char m_cwd [256];
char const *m_cfs;
fs_list m_fs;
};

View File

@@ -1,6 +1,7 @@
#include <stdint.h> #include <stdint.h>
#include <j6/flags.h> #include <j6/flags.h>
#include <j6/errors.h> #include <j6/errors.h>
#include <j6/memutils.h>
#include <j6/protocols/vfs.h> #include <j6/protocols/vfs.h>
#include <j6/syscalls.h> #include <j6/syscalls.h>
#include <j6/syslog.hh> #include <j6/syslog.hh>
@@ -11,6 +12,9 @@
static uint64_t initfs_running = 1; static uint64_t initfs_running = 1;
static constexpr size_t buffer_size = 2048; static constexpr size_t buffer_size = 2048;
static char fs_tag[] = "init";
static constexpr size_t fs_tag_len = sizeof(fs_tag) - 1;
j6_status_t j6_status_t
handle_load_request(j6romfs::fs &fs, const char *path, j6_handle_t &vma) handle_load_request(j6romfs::fs &fs, const char *path, j6_handle_t &vma)
{ {
@@ -82,6 +86,14 @@ initfs_start(j6romfs::fs &fs, j6_handle_t mb)
tag = j6_proto_vfs_file; tag = j6_proto_vfs_file;
break; break;
case j6_proto_vfs_get_tag:
out_len = fs_tag_len;
handles_count = 0;
tag = j6_proto_vfs_tag;
memcpy(buffer, fs_tag, fs_tag_len);
break;
default: default:
tag = j6_proto_base_status; tag = j6_proto_base_status;
*reinterpret_cast<j6_status_t*>(buffer) = j6_err_invalid_arg; *reinterpret_cast<j6_status_t*>(buffer) = j6_err_invalid_arg;
@@ -90,7 +102,6 @@ initfs_start(j6romfs::fs &fs, j6_handle_t mb)
handles_count = 0; handles_count = 0;
} }
out_len = buffer_size;
s = j6_mailbox_respond(mb, &tag, s = j6_mailbox_respond(mb, &tag,
buffer, &out_len, buffer_size, buffer, &out_len, buffer_size,
&give_handle, &handles_count, max_handles, &give_handle, &handles_count, max_handles,