diff --git a/repos/gems/lib/mk/vfs_pipe.mk b/repos/gems/lib/mk/vfs_pipe.mk new file mode 100644 index 000000000..9b3ef9a3d --- /dev/null +++ b/repos/gems/lib/mk/vfs_pipe.mk @@ -0,0 +1,5 @@ +SRC_CC = plugin.cc + +vpath %.cc $(REP_DIR)/src/lib/vfs/pipe + +SHARED_LIB = yes diff --git a/repos/gems/recipes/src/vfs_pipe/content.mk b/repos/gems/recipes/src/vfs_pipe/content.mk new file mode 100644 index 000000000..9e0246b49 --- /dev/null +++ b/repos/gems/recipes/src/vfs_pipe/content.mk @@ -0,0 +1,9 @@ +MIRROR_FROM_REP_DIR := lib/mk/vfs_pipe.mk src/lib/vfs/pipe + +content: $(MIRROR_FROM_REP_DIR) LICENSE + +$(MIRROR_FROM_REP_DIR): + $(mirror_from_rep_dir) + +LICENSE: + cp $(GENODE_DIR)/LICENSE $@ diff --git a/repos/gems/recipes/src/vfs_pipe/hash b/repos/gems/recipes/src/vfs_pipe/hash new file mode 100644 index 000000000..d8ea98806 --- /dev/null +++ b/repos/gems/recipes/src/vfs_pipe/hash @@ -0,0 +1 @@ +2019-06-04 ecacc703584c04e70085ad12628ee40885e9e50c diff --git a/repos/gems/recipes/src/vfs_pipe/used_apis b/repos/gems/recipes/src/vfs_pipe/used_apis new file mode 100644 index 000000000..6069d7955 --- /dev/null +++ b/repos/gems/recipes/src/vfs_pipe/used_apis @@ -0,0 +1,4 @@ +base +os +so +vfs diff --git a/repos/gems/src/lib/vfs/pipe/README b/repos/gems/src/lib/vfs/pipe/README new file mode 100644 index 000000000..95e40e6fc --- /dev/null +++ b/repos/gems/src/lib/vfs/pipe/README @@ -0,0 +1,12 @@ +The VFS pipe plugin exposes a control file for creating pipes and a set of pipe +directories. Opening and reading the "/new" returns a relative path to a +directory. That directory represents a pipe and contains an "in" and "out" file +for writing and reading respectively to the pipe. + +Reads and writes are non-blocking and will complete short operations without +error, with the exception of reads on an empty pipe, which return READ_QUEUED. +The read and write capacity of a pipe may be queried by stat'ing the size of +"out" and "in" files. + +When all "in" and "out" handles on a pipe as well as the initial handle on "new" +are closed, the pipe is destroyed. diff --git a/repos/gems/src/lib/vfs/pipe/plugin.cc b/repos/gems/src/lib/vfs/pipe/plugin.cc new file mode 100644 index 000000000..bf880f53a --- /dev/null +++ b/repos/gems/src/lib/vfs/pipe/plugin.cc @@ -0,0 +1,618 @@ +/* + * \brief VFS pipe plugin + * \author Emery Hemingway + * \date 2019-05-29 + */ + +/* + * Copyright (C) 2019 Genode Labs GmbH + * + * This file is part of the Genode OS framework, which is distributed + * under the terms of the GNU Affero General Public License version 3. + */ + +#include +#include +#include +#include + +namespace Vfs_pipe { + using namespace Vfs; + typedef Vfs::Directory_service::Open_result Open_result; + typedef Vfs::File_io_service::Write_result Write_result; + typedef Vfs::File_io_service::Read_result Read_result; + typedef Genode::Path<32> Path; + + enum { PIPE_BUF_SIZE = 8192U }; + typedef Genode::Ring_buffer Pipe_buffer; + + struct Pipe_handle; + typedef Genode::Fifo_element Handle_element; + typedef Genode::Fifo Handle_fifo; + typedef Genode::Registry::Element Pipe_handle_registry_element; + typedef Genode::Registry Pipe_handle_registry; + + class Pipe; + typedef Genode::Id_space Pipe_space; + + struct New_pipe_handle; + + class File_system; +} + + +struct Vfs_pipe::Pipe_handle : Vfs::Vfs_handle, private Pipe_handle_registry_element +{ + Pipe &pipe; + + Handle_element io_progress_elem { *this }; + Handle_element read_ready_elem { *this }; + + bool const writer; + + Pipe_handle(Vfs::File_system &fs, + Genode::Allocator &alloc, + unsigned flags, + Pipe_handle_registry ®istry, + Pipe &p) + : + Vfs::Vfs_handle(fs, fs, alloc, flags), + Pipe_handle_registry_element(registry, *this), + pipe(p), + writer(flags == Directory_service::OPEN_MODE_WRONLY) + { } + + virtual ~Pipe_handle(); + + Write_result write(const char *buf, + file_size count, + file_size &out_count); + + Read_result read(char *buf, + file_size count, + file_size &out_count); + + bool read_ready(); + bool notify_read_ready(); +}; + + +struct Vfs_pipe::Pipe +{ + Genode::Allocator &alloc; + Pipe_space::Element space_elem; + Pipe_buffer buffer { }; + Pipe_handle_registry registry { }; + Handle_fifo io_progress_waiters { }; + Handle_fifo read_ready_waiters { }; + unsigned num_writers = 0; + + Genode::Signal_context_capability ¬ify_sigh; + + bool new_handle_active { true }; + + Pipe(Genode::Allocator &alloc, Pipe_space &space, + Genode::Signal_context_capability ¬ify_sigh) + : alloc(alloc), space_elem(*this, space), notify_sigh(notify_sigh) { } + + ~Pipe() { } + + typedef Genode::String<8> Name; + Name name() const + { + return Name(space_elem.id().value); + } + + /** + * Check if pipe is referenced, if not, destroy + */ + void cleanup() + { + bool alive = new_handle_active; + if (!alive) + registry.for_each([&alive] (Pipe_handle&) { + alive = true; }); + if (!alive) + destroy(alloc, this); + } + + /** + * Remove "/new" handle reference + */ + void remove_new_handle() { + new_handle_active = false; } + + /** + * Detach a handle + */ + void remove(Pipe_handle &handle) + { + if (handle.io_progress_elem.enqueued()) + io_progress_waiters.remove(handle.io_progress_elem); + if (handle.read_ready_elem.enqueued()) + read_ready_waiters.remove(handle.read_ready_elem); + } + + /** + * Open a write or read handle + */ + Open_result open(Vfs::File_system &fs, + Path const &filename, + Vfs::Vfs_handle **handle, + Genode::Allocator &alloc) + { + if (filename == "/in") { + *handle = new (alloc) + Pipe_handle(fs, alloc, Directory_service::OPEN_MODE_WRONLY, registry, *this); + num_writers++; + return Open_result::OPEN_OK; + } + + if (filename == "/out") { + *handle = new (alloc) + Pipe_handle(fs, alloc, Directory_service::OPEN_MODE_RDONLY, registry, *this); + return Open_result::OPEN_OK; + } + + return Open_result::OPEN_ERR_UNACCESSIBLE; + } + + /** + * Use a signal as a hack to defer notifications + * until the "io_progress_handler". + */ + void submit_signal() { + Genode::Signal_transmitter(notify_sigh).submit(); } + + /** + * Notify handles waiting for activity + */ + void notify() + { + io_progress_waiters.dequeue_all([] (Handle_element &elem) { + elem.object().io_progress_response(); }); + read_ready_waiters.dequeue_all([] (Handle_element &elem) { + elem.object().read_ready_response(); }); + } + + Write_result write(Pipe_handle &handle, + const char *buf, file_size count, + file_size &out_count) + { + file_size out = 0; + bool notify = buffer.empty(); + + while (out < count && 0 < buffer.avail_capacity()) { + buffer.add(*(buf++)); + ++out; + } + + out_count = out; + if (out < count) + io_progress_waiters.enqueue(handle.io_progress_elem); + + if (notify) + submit_signal(); + + return Write_result::WRITE_OK; + } + + Read_result read(Pipe_handle &handle, + char *buf, file_size count, + file_size &out_count) + { + bool notify = buffer.avail_capacity() == 0; + + file_size out = 0; + while (out < count && !buffer.empty()) { + *(buf++) = buffer.get(); + ++out; + } + + out_count = out; + if (!out) { + + if (num_writers == 0) + return Read_result::READ_OK; /* EOF */ + + io_progress_waiters.enqueue(handle.io_progress_elem); + return Read_result::READ_QUEUED; + } + + if (notify) + submit_signal(); + + return Read_result::READ_OK; + } +}; + + +Vfs_pipe::Pipe_handle::~Pipe_handle() { + pipe.remove(*this); } + + +Vfs_pipe::Write_result +Vfs_pipe::Pipe_handle::write(const char *buf, + file_size count, + file_size &out_count) { + return Pipe_handle::pipe.write(*this, buf, count, out_count); } + + +Vfs_pipe::Read_result +Vfs_pipe::Pipe_handle::read(char *buf, + file_size count, + file_size &out_count) { + return Pipe_handle::pipe.read(*this, buf, count, out_count); } + + +bool +Vfs_pipe::Pipe_handle::read_ready() { + return !pipe.buffer.empty(); } + + +bool +Vfs_pipe::Pipe_handle::notify_read_ready() +{ + if (!read_ready_elem.enqueued()) + pipe.read_ready_waiters.enqueue(read_ready_elem); + return true; +} + + +struct Vfs_pipe::New_pipe_handle : Vfs::Vfs_handle +{ + Pipe &pipe; + + New_pipe_handle(Vfs::File_system &fs, + Genode::Allocator &alloc, + unsigned flags, + Pipe_space &pipe_space, + Genode::Signal_context_capability ¬ify_sigh) + : Vfs::Vfs_handle(fs, fs, alloc, flags), + pipe(*(new (alloc) Pipe(alloc, pipe_space, notify_sigh))) + { } + + ~New_pipe_handle() + { + pipe.remove_new_handle(); + } + + Read_result read(char *buf, + file_size count, + file_size &out_count) + { + auto name = pipe.name(); + if (name.length() < count) { + memcpy(buf, name.string(), name.length()); + out_count = name.length(); + return Read_result::READ_OK; + } + return Read_result::READ_ERR_INVALID; + } +}; + + +class Vfs_pipe::File_system : public Vfs::File_system +{ + private: + + Pipe_space _pipe_space { }; + + /* + * XXX: a hack to defer cross-thread notifications at + * the libc until the io_progress handler + */ + Genode::Io_signal_handler _notify_handler; + Genode::Signal_context_capability _notify_cap { _notify_handler }; + + void _notify_any() + { + _pipe_space.for_each([] (Pipe &pipe) { + pipe.notify(); }); + } + + public: + + File_system(Vfs::Env &env) + : _notify_handler(env.env().ep(), *this, &File_system::_notify_any) { } + + const char* type() override { return "pipe"; } + + /*********************** + ** Directory service ** + ***********************/ + + Genode::Dataspace_capability dataspace(char const*) override { + return Genode::Dataspace_capability(); } + + void release(char const*, Dataspace_capability) override { } + + Open_result open(const char *cpath, + unsigned mode, + Vfs::Vfs_handle **handle, + Genode::Allocator &alloc) override + { + Path path(cpath); + + if (path == "/new") { + if ((Directory_service::OPEN_MODE_ACCMODE & mode) == Directory_service::OPEN_MODE_WRONLY) + return Open_result::OPEN_ERR_NO_PERM; + *handle = new (alloc) + New_pipe_handle(*this, alloc, mode, _pipe_space, _notify_cap); + return Open_result::OPEN_OK; + } + + path.strip_last_element(); + if (!path.has_single_element()) + return Open_result::OPEN_ERR_UNACCESSIBLE; + + Pipe_space::Id id { ~0UL }; + if (!ascii_to(path.last_element(), id.value)) + return Open_result::OPEN_ERR_UNACCESSIBLE; + + Open_result result = Open_result::OPEN_ERR_UNACCESSIBLE; + try { + _pipe_space.apply(id, [&] (Pipe &pipe) { + Path filename(cpath); + filename.keep_only_last_element(); + result = pipe.open(*this, filename, handle, alloc); + }); + } + catch (Pipe_space::Unknown_id) { } + + return result; + } + + Opendir_result opendir(char const *cpath, bool create, + Vfs_handle **handle, + Allocator &alloc) override + { + /* open dummy handles on directories */ + + if (create) return OPENDIR_ERR_PERMISSION_DENIED; + Path path(cpath); + + if (path == "/") { + *handle = new (alloc) + Vfs_handle(*this, *this, alloc, 0); + return OPENDIR_OK; + } + + Opendir_result result { OPENDIR_ERR_LOOKUP_FAILED }; + + if (path.has_single_element()) { + Pipe_space::Id id { ~0UL }; + if (ascii_to(path.last_element(), id.value)) try { + _pipe_space.apply(id, [&] (Pipe&) { + *handle = new (alloc) + Vfs_handle(*this, *this, alloc, 0); + result = OPENDIR_OK; + }); + } + catch (Pipe_space::Unknown_id) { } + } + + return result; + } + + void close(Vfs::Vfs_handle *vfs_handle) override + { + Pipe *pipe = nullptr; + if (Pipe_handle *handle = dynamic_cast(vfs_handle)) { + pipe = &handle->pipe; + if (handle->writer) + pipe->num_writers--; + } else + if (New_pipe_handle *handle = dynamic_cast(vfs_handle)) + pipe = &handle->pipe; + + destroy(vfs_handle->alloc(), vfs_handle); + + if (pipe) + pipe->cleanup(); + } + + Stat_result stat(const char *cpath, Stat &out) override + { + Stat_result result { STAT_ERR_NO_ENTRY }; + Path path(cpath); + + out = Stat { }; + + if (path == "/new") { + out = Stat { + .size = 1, + .type = Node_type::TRANSACTIONAL_FILE, + .rwx = Node_rwx::wo(), + .inode = Genode::addr_t(this), + .device = Genode::addr_t(this), + .modification_time = { } + }; + return STAT_OK; + } + + if (path.has_single_element()) { + Pipe_space::Id id { ~0UL }; + if (ascii_to(path.last_element(), id.value)) try { + _pipe_space.apply(id, [&] (Pipe &pipe) { + out = Stat { + .size = 2, + .type = Node_type::DIRECTORY, + .rwx = Node_rwx::rwx(), + .inode = Genode::addr_t(&pipe), + .device = Genode::addr_t(this), + .modification_time = { } + }; + result = STAT_OK; + }); + } + catch (Pipe_space::Unknown_id) { } + } else { + /* maybe this is /N/in or /N/out */ + path.strip_last_element(); + if (!path.has_single_element()) + /* too many directory levels */ + return result; + + Pipe_space::Id id { ~0UL }; + if (ascii_to(path.last_element(), id.value)) try { + _pipe_space.apply(id, [&] (Pipe &pipe) { + Path filename(cpath); + filename.keep_only_last_element(); + if (filename == "/in") { + out = Stat { + .size = file_size(pipe.buffer.avail_capacity()), + .type = Node_type::CONTINUOUS_FILE, + .rwx = Node_rwx::wo(), + .inode = Genode::addr_t(&pipe) + 1, + .device = Genode::addr_t(this), + .modification_time = { } + }; + result = STAT_OK; + } else + if (filename == "/out") { + out = Stat { + .size = file_size(PIPE_BUF_SIZE + - pipe.buffer.avail_capacity()), + .type = Node_type::CONTINUOUS_FILE, + .rwx = Node_rwx::ro(), + .inode = Genode::addr_t(&pipe) + 2, + .device = Genode::addr_t(this), + .modification_time = { } + }; + result = STAT_OK; + } + }); + } + catch (Pipe_space::Unknown_id) { } + } + + return result; + } + + Unlink_result unlink(const char*) override { + return UNLINK_ERR_NO_ENTRY; } + + Rename_result rename(const char*, const char*) override { + return RENAME_ERR_NO_ENTRY; } + + file_size num_dirent(char const *) override { + return ~0UL; } + + bool directory(char const *cpath) override + { + Path path(cpath); + if (path == "/") return true; + + if (!path.has_single_element()) + return Open_result::OPEN_ERR_UNACCESSIBLE; + + Pipe_space::Id id { ~0UL }; + if (!ascii_to(path.last_element(), id.value)) + return false; + + bool result = false; + try { + _pipe_space.apply(id, [&] (Pipe &) { + result = true; }); + } + catch (Pipe_space::Unknown_id) { } + + return result; + } + + const char* leaf_path(const char *cpath) override + { + Path path(cpath); + if (path == "/") return cpath; + if (path == "/new") return cpath; + + char const *result = nullptr; + if (!path.has_single_element()) { + /* maybe this is /N/in or /N/out */ + path.strip_last_element(); + if (!path.has_single_element()) + /* too many directory levels */ + return nullptr; + + Path filename(cpath); + filename.keep_only_last_element(); + if (filename != "/in" && filename != "/out") + /* not a pipe file */ + return nullptr; + } + + Pipe_space::Id id { ~0UL }; + if (ascii_to(path.last_element(), id.value)) try { + /* check if the pipe directory exists */ + _pipe_space.apply(id, [&] (Pipe &) { + result = cpath; }); + } + catch (Pipe_space::Unknown_id) { } + + return result; + } + + /********************** + ** File I/O service ** + **********************/ + + Write_result write(Vfs_handle *vfs_handle, + const char *src, file_size count, + file_size &out_count) override + { + if (Pipe_handle *handle = dynamic_cast(vfs_handle)) + return handle->write(src, count, out_count); + + return WRITE_ERR_INVALID; + } + + Read_result complete_read(Vfs_handle *vfs_handle, + char *dst, file_size count, + file_size &out_count) override + { + if (Pipe_handle *handle = dynamic_cast(vfs_handle)) + return handle->read(dst, count, out_count); + + if (New_pipe_handle *handle = dynamic_cast(vfs_handle)) + return handle->read(dst, count, out_count); + + return READ_ERR_INVALID; + } + + bool read_ready(Vfs_handle *vfs_handle) override + { + if (Pipe_handle *handle = dynamic_cast(vfs_handle)) + return handle->read_ready(); + return true; + } + + bool notify_read_ready(Vfs_handle *vfs_handle) override + { + if (Pipe_handle *handle = dynamic_cast(vfs_handle)) + return handle->notify_read_ready(); + return false; + } + + Ftruncate_result ftruncate(Vfs_handle*, file_size) override { + return FTRUNCATE_ERR_NO_PERM; } + + Sync_result complete_sync(Vfs_handle*) override { + return SYNC_OK; } +}; + + +extern "C" Vfs::File_system_factory *vfs_file_system_factory(void) +{ + struct Factory : Vfs::File_system_factory + { + Vfs::File_system *create(Vfs::Env &env, Genode::Xml_node) override + { + return new (env.alloc()) + Vfs_pipe::File_system(env); + } + }; + + static Factory f; + return &f; +} diff --git a/repos/gems/src/lib/vfs/pipe/target.mk b/repos/gems/src/lib/vfs/pipe/target.mk new file mode 100644 index 000000000..d2d34db6b --- /dev/null +++ b/repos/gems/src/lib/vfs/pipe/target.mk @@ -0,0 +1,2 @@ +TARGET = dummy-vfs_pipe +LIBS = vfs_pipe diff --git a/repos/libports/recipes/pkg/test-libc_pipe/archives b/repos/libports/recipes/pkg/test-libc_pipe/archives index b9781b6a5..2e4192267 100644 --- a/repos/libports/recipes/pkg/test-libc_pipe/archives +++ b/repos/libports/recipes/pkg/test-libc_pipe/archives @@ -2,4 +2,6 @@ _/src/init _/src/test-libc_pipe _/src/libc _/src/vfs +_/src/vfs_pipe _/src/posix +_/src/sequence diff --git a/repos/libports/recipes/pkg/test-libc_pipe/runtime b/repos/libports/recipes/pkg/test-libc_pipe/runtime index a23f40ffd..ed0eb8f17 100644 --- a/repos/libports/recipes/pkg/test-libc_pipe/runtime +++ b/repos/libports/recipes/pkg/test-libc_pipe/runtime @@ -2,40 +2,71 @@ - child "test-libc_pipe" exited with exit value 0 + child "sequence" exited with exit value 0 Error: - - + + + + - - - + - - + + + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/repos/libports/recipes/src/test-libc_pipe/content.mk b/repos/libports/recipes/src/test-libc_pipe/content.mk index 7af7881c3..85d6481dc 100644 --- a/repos/libports/recipes/src/test-libc_pipe/content.mk +++ b/repos/libports/recipes/src/test-libc_pipe/content.mk @@ -1,11 +1,2 @@ SRC_DIR = src/test/libc_pipe include $(GENODE_DIR)/repos/base/recipes/src/content.inc - -MIRROR_FROM_REP_DIR := include/libc-plugin \ - lib/mk/libc_pipe.mk \ - src/lib/libc_pipe - -content: $(MIRROR_FROM_REP_DIR) - -$(MIRROR_FROM_REP_DIR): - $(mirror_from_rep_dir) diff --git a/repos/libports/src/lib/libc/internal/vfs_plugin.h b/repos/libports/src/lib/libc/internal/vfs_plugin.h index d2016e852..81e8960a3 100644 --- a/repos/libports/src/lib/libc/internal/vfs_plugin.h +++ b/repos/libports/src/lib/libc/internal/vfs_plugin.h @@ -78,6 +78,7 @@ class Libc::Vfs_plugin : public Plugin Constructible _root_dir { }; Vfs::Io_response_handler &_response_handler; Update_mtime const _update_mtime; + bool const _pipe_configured; /** * Sync a handle and propagate errors @@ -102,6 +103,14 @@ class Libc::Vfs_plugin : public Plugin template void _with_info(File_descriptor &fd, FN const &fn); + static bool _init_pipe_configured(Xml_node config) + { + bool result = false; + config.with_sub_node("libc", [&] (Xml_node libc_node) { + result = libc_node.has_attribute("pipe"); }); + return result; + } + public: Vfs_plugin(Libc::Env &env, @@ -114,7 +123,8 @@ class Libc::Vfs_plugin : public Plugin _alloc(alloc), _root_fs(env.vfs()), _response_handler(handler), - _update_mtime(update_mtime) + _update_mtime(update_mtime), + _pipe_configured(_init_pipe_configured(config)) { if (config.has_sub_node("libc")) _root_dir.construct(vfs_env); @@ -134,6 +144,7 @@ class Libc::Vfs_plugin : public Plugin bool supports_access(const char *, int) override { return true; } bool supports_mkdir(const char *, mode_t) override { return true; } bool supports_open(const char *, int) override { return true; } + bool supports_pipe() override { return _pipe_configured; } bool supports_poll() override { return true; } bool supports_readlink(const char *, char *, ::size_t) override { return true; } bool supports_rename(const char *, const char *) override { return true; } @@ -167,6 +178,7 @@ class Libc::Vfs_plugin : public Plugin int ioctl(File_descriptor *, int , char *) override; ::off_t lseek(File_descriptor *fd, ::off_t offset, int whence) override; int mkdir(const char *, mode_t) override; + int pipe(File_descriptor *pipefdo[2]) override; bool poll(File_descriptor &fdo, struct pollfd &pfd) override; ssize_t read(File_descriptor *, void *, ::size_t) override; ssize_t readlink(const char *, char *, ::size_t) override; diff --git a/repos/libports/src/lib/libc/vfs_plugin.cc b/repos/libports/src/lib/libc/vfs_plugin.cc index 3cb9dbbb5..ef8a9c72c 100644 --- a/repos/libports/src/lib/libc/vfs_plugin.cc +++ b/repos/libports/src/lib/libc/vfs_plugin.cc @@ -166,6 +166,13 @@ namespace Libc { char const *string() const { return _value.string(); } }; + char const *config_pipe() __attribute__((weak)); + char const *config_pipe() + { + static Config_attr attr("pipe", ""); + return attr.string(); + } + char const *config_rng() __attribute__((weak)); char const *config_rng() { @@ -1599,6 +1606,65 @@ int Libc::Vfs_plugin::munmap(void *addr, ::size_t) } +int Libc::Vfs_plugin::pipe(Libc::File_descriptor *pipefdo[2]) +{ + Absolute_path base_path(Libc::config_pipe()); + if (base_path == "") { + error(__func__, ": pipe fs not mounted"); + return Errno(EACCES); + } + + Libc::File_descriptor *meta_fd { nullptr }; + + { + Absolute_path new_path = base_path; + new_path.append("/new"); + + meta_fd = open(new_path.base(), O_RDONLY, Libc::ANY_FD); + if (!meta_fd) { + Genode::error("failed to create pipe at ", new_path); + return Errno(EACCES); + } + meta_fd->path(new_path.string()); + + char buf[32] { }; + int const n = read(meta_fd, buf, sizeof(buf)-1); + if (n < 1) { + error("failed to read pipe at ", new_path); + close(meta_fd); + return Errno(EACCES); + } + buf[n] = '\0'; + base_path.append("/"); + base_path.append(buf); + } + + auto open_pipe_fd = [&] (auto path_suffix, auto flags) + { + Absolute_path path = base_path; + path.append(path_suffix); + + File_descriptor *fd = open(path.base(), flags, Libc::ANY_FD); + if (!fd) + error("failed to open pipe end at ", path); + else + fd->path(path.string()); + + return fd; + }; + + pipefdo[0] = open_pipe_fd("/out", O_RDONLY); + pipefdo[1] = open_pipe_fd("/in", O_WRONLY); + + close(meta_fd); + + if (!pipefdo[0] || !pipefdo[1]) + return Errno(EACCES); + + return 0; +} + + bool Libc::Vfs_plugin::poll(File_descriptor &fd, struct pollfd &pfd) { if (fd.plugin != this) return false; diff --git a/repos/libports/src/test/libc_pipe/main.cc b/repos/libports/src/test/libc_pipe/main.cc index 816dc99bf..f4f691325 100644 --- a/repos/libports/src/test/libc_pipe/main.cc +++ b/repos/libports/src/test/libc_pipe/main.cc @@ -76,7 +76,8 @@ int main(int argc, char *argv[]) ssize_t bytes_written = write(pipefd[1], buf, BUF_SIZE); if (bytes_written != BUF_SIZE) { - fprintf(stderr, "Error writing to pipe\n"); + fprintf(stderr, "Error writing to pipe (bytes_written=%zd, BUF_SIZE=%zd)\n", + bytes_written, (size_t)BUF_SIZE); exit(1); } diff --git a/repos/libports/src/test/libc_pipe/target.mk b/repos/libports/src/test/libc_pipe/target.mk index fb24f5958..00bd7025e 100644 --- a/repos/libports/src/test/libc_pipe/target.mk +++ b/repos/libports/src/test/libc_pipe/target.mk @@ -1,5 +1,5 @@ TARGET = test-libc_pipe -LIBS = base posix libc_pipe +LIBS = base posix SRC_CC = main.cc CC_CXX_WARN_STRICT = diff --git a/repos/os/include/vfs/types.h b/repos/os/include/vfs/types.h index f2733966b..917f795cb 100644 --- a/repos/os/include/vfs/types.h +++ b/repos/os/include/vfs/types.h @@ -72,6 +72,10 @@ namespace Vfs { .writeable = false, .executable = false }; } + static Node_rwx wo() { return { .readable = false, + .writeable = true, + .executable = false }; } + static Node_rwx rw() { return { .readable = true, .writeable = true, .executable = false }; }