From eb62588b790735b993636690c4e8c5bb20db7d80 Mon Sep 17 00:00:00 2001 From: "Justin C. Miller" Date: Tue, 30 Apr 2024 22:23:04 -0700 Subject: [PATCH] [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. --- src/libraries/j6/include/j6/protocols/vfs.h | 4 +- src/libraries/j6/include/j6/protocols/vfs.hh | 15 ++++++- src/libraries/j6/protocols/vfs.cpp | 32 ++++++++++++++ src/user/6s/6s.module | 1 + src/user/6s/commands.cpp | 38 ++++++++++++++--- src/user/6s/commands.h | 9 ++-- src/user/6s/main.cpp | 45 +++++++++----------- src/user/6s/shell.cpp | 43 +++++++++++++++++++ src/user/6s/shell.h | 38 +++++++++++++++++ src/user/srv.init/initfs.cpp | 13 +++++- 10 files changed, 195 insertions(+), 43 deletions(-) create mode 100644 src/user/6s/shell.cpp create mode 100644 src/user/6s/shell.h diff --git a/src/libraries/j6/include/j6/protocols/vfs.h b/src/libraries/j6/include/j6/protocols/vfs.h index baa4dd8..f089e5c 100644 --- a/src/libraries/j6/include/j6/protocols/vfs.h +++ b/src/libraries/j6/include/j6/protocols/vfs.h @@ -8,4 +8,6 @@ enum j6_proto_vfs_tag { j6_proto_vfs_load = j6_proto_base_first_proto_id, j6_proto_vfs_file, -}; \ No newline at end of file + j6_proto_vfs_get_tag, + j6_proto_vfs_tag, +}; diff --git a/src/libraries/j6/include/j6/protocols/vfs.hh b/src/libraries/j6/include/j6/protocols/vfs.hh index 4699234..c0033c0 100644 --- a/src/libraries/j6/include/j6/protocols/vfs.hh +++ b/src/libraries/j6/include/j6/protocols/vfs.hh @@ -13,7 +13,13 @@ class API client public: /// Constructor. /// \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 /// \arg path Path of the file to load @@ -21,8 +27,13 @@ public: /// \arg size [out] Size of the file 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: j6_handle_t m_service; }; -} // namespace j6::proto::vfs \ No newline at end of file +} // namespace j6::proto::vfs diff --git a/src/libraries/j6/protocols/vfs.cpp b/src/libraries/j6/protocols/vfs.cpp index 3476df2..0e0ce4e 100644 --- a/src/libraries/j6/protocols/vfs.cpp +++ b/src/libraries/j6/protocols/vfs.cpp @@ -1,3 +1,4 @@ +#include "j6/types.h" #include #include #include @@ -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; } 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(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 #endif // __j6kernel diff --git a/src/user/6s/6s.module b/src/user/6s/6s.module index 50d0c04..b9a908f 100644 --- a/src/user/6s/6s.module +++ b/src/user/6s/6s.module @@ -7,4 +7,5 @@ module("6s", sources = [ "commands.cpp", "main.cpp", + "shell.cpp", ]) diff --git a/src/user/6s/commands.cpp b/src/user/6s/commands.cpp index 33546ca..108586f 100644 --- a/src/user/6s/commands.cpp +++ b/src/user/6s/commands.cpp @@ -1,23 +1,45 @@ #include #include #include "commands.h" +#include "shell.h" static void -help(edit::source &s) +fslist(shell &s) { + char line[100]; + util::counted output { line, sizeof(line) }; + + 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 output { line, sizeof(line) }; + for (unsigned i = 0; i < g_builtins_count; ++i) { - char line[100]; - util::counted output { line, sizeof(line) }; - builtin &cmd = g_builtins[i]; - size_t len = util::format(output, "%20s - %s\r\n", cmd.name(), cmd.description()); s.write(line, len); } } static void -version(edit::source &s) +pwd(shell &s) +{ + char line[100]; + util::counted 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; @@ -29,7 +51,9 @@ version(edit::source &s) } 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 }, }; size_t g_builtins_count = sizeof(g_builtins) / sizeof(g_builtins[0]); diff --git a/src/user/6s/commands.h b/src/user/6s/commands.h index 5394452..37975fe 100644 --- a/src/user/6s/commands.h +++ b/src/user/6s/commands.h @@ -2,15 +2,12 @@ #include -namespace edit { - class source; -} - +struct shell; class builtin { public: - using runf = void (*)(edit::source &); + using runf = void (*)(shell &); builtin(const char *name, const char *desc, runf func) : m_name {name}, m_desc {desc}, m_func {func} {} @@ -18,7 +15,7 @@ public: const char * name() const { return m_name; } const char * description() const { return m_desc; } - void run(edit::source &s) { m_func(s); } + void run(shell &s) { m_func(s); } private: const char *m_name; diff --git a/src/user/6s/main.cpp b/src/user/6s/main.cpp index c489ca4..0a283e7 100644 --- a/src/user/6s/main.cpp +++ b/src/user/6s/main.cpp @@ -11,13 +11,13 @@ #include #include -#include "commands.h" +#include "shell.h" extern "C" { 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"; 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; -void handle_command(edit::source &s, const char *command, size_t len); class channel_source : public edit::source @@ -47,9 +46,13 @@ public: void write(char const *data, size_t len) override { uint8_t *outp; - m_chan.reserve(len, &outp); - memcpy(outp, data, len); - m_chan.commit(len); + while (len) { + size_t size = m_chan.reserve(len, &outp); + size_t n = len < size ? len : size; + memcpy(outp, data, n); + m_chan.commit(n); + len -= n; + } } private: @@ -63,14 +66,20 @@ main(int argc, const char **argv) j6_handle_t event = j6_handle_invalid; j6_status_t result = j6_status_ok; + /* g_handle_sys = j6_find_init_handle(0); if (g_handle_sys == j6_handle_invalid) return 1; + */ j6_handle_t slp = j6_find_init_handle(j6::proto::sl::id); if (slp == j6_handle_invalid) 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; j6::proto::sl::client slp_client {slp}; @@ -95,6 +104,9 @@ main(int argc, const char **argv) channel_source source {*cout}; edit::line editor {source}; + shell sh { source }; + sh.add_filesystem(vfs); + static constexpr size_t bufsize = 256; char buffer [bufsize]; @@ -102,25 +114,6 @@ main(int argc, const char **argv) while (true) { 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); -} diff --git a/src/user/6s/shell.cpp b/src/user/6s/shell.cpp new file mode 100644 index 0000000..22529b4 --- /dev/null +++ b/src/user/6s/shell.cpp @@ -0,0 +1,43 @@ +#include +#include +#include +#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); +} diff --git a/src/user/6s/shell.h b/src/user/6s/shell.h new file mode 100644 index 0000000..02ff1b5 --- /dev/null +++ b/src/user/6s/shell.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include + +/// Shell state +class shell +{ +public: + struct fs { + const char *tag; + j6::proto::vfs::client client; + }; + using fs_list = std::vector; + + 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; +}; diff --git a/src/user/srv.init/initfs.cpp b/src/user/srv.init/initfs.cpp index 19ce08c..b0f4fcf 100644 --- a/src/user/srv.init/initfs.cpp +++ b/src/user/srv.init/initfs.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -11,6 +12,9 @@ static uint64_t initfs_running = 1; 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 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; 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: tag = j6_proto_base_status; *reinterpret_cast(buffer) = j6_err_invalid_arg; @@ -90,7 +102,6 @@ initfs_start(j6romfs::fs &fs, j6_handle_t mb) handles_count = 0; } - out_len = buffer_size; s = j6_mailbox_respond(mb, &tag, buffer, &out_len, buffer_size, &give_handle, &handles_count, max_handles,