2016-05-25 15:47:22 +02:00
|
|
|
/*
|
2017-02-01 11:28:15 +01:00
|
|
|
* \brief Libc plugin for using a process-local virtual file system
|
|
|
|
* \author Norman Feske
|
|
|
|
* \author Emery Hemingway
|
|
|
|
* \author Christian Helmuth
|
|
|
|
* \date 2014-04-09
|
2016-05-25 15:47:22 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
2019-03-25 15:41:43 +01:00
|
|
|
* Copyright (C) 2014-2019 Genode Labs GmbH
|
2016-05-25 15:47:22 +02:00
|
|
|
*
|
|
|
|
* This file is part of the Genode OS framework, which is distributed
|
2017-02-20 13:23:52 +01:00
|
|
|
* under the terms of the GNU Affero General Public License version 3.
|
2016-05-25 15:47:22 +02:00
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _LIBC_VFS__PLUGIN_H_
|
|
|
|
#define _LIBC_VFS__PLUGIN_H_
|
|
|
|
|
|
|
|
/* Genode includes */
|
2017-01-03 14:33:55 +01:00
|
|
|
#include <libc/component.h>
|
2016-05-25 15:47:22 +02:00
|
|
|
|
|
|
|
/* libc includes */
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
/* libc plugin interface */
|
|
|
|
#include <libc-plugin/plugin.h>
|
|
|
|
#include <libc-plugin/fd_alloc.h>
|
|
|
|
|
2017-12-13 00:32:49 +01:00
|
|
|
/* local includes */
|
|
|
|
#include "task.h"
|
|
|
|
#include "libc_errno.h"
|
|
|
|
|
|
|
|
|
2016-05-25 15:47:22 +02:00
|
|
|
namespace Libc { class Vfs_plugin; }
|
|
|
|
|
|
|
|
|
|
|
|
class Libc::Vfs_plugin : public Libc::Plugin
|
|
|
|
{
|
|
|
|
private:
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
Genode::Allocator &_alloc;
|
|
|
|
Vfs::File_system &_root_dir;
|
|
|
|
Vfs::Io_response_handler &_response_handler;
|
2016-05-25 15:47:22 +02:00
|
|
|
|
2017-01-03 14:33:55 +01:00
|
|
|
void _open_stdio(Genode::Xml_node const &node, char const *attr,
|
|
|
|
int libc_fd, unsigned flags)
|
2016-05-25 15:47:22 +02:00
|
|
|
{
|
2019-01-21 15:59:00 +01:00
|
|
|
if (!node.has_attribute(attr)) {
|
|
|
|
Libc::file_descriptor_allocator()->alloc(nullptr, nullptr, libc_fd);
|
|
|
|
return;
|
|
|
|
}
|
2017-01-03 14:33:55 +01:00
|
|
|
|
2019-01-21 15:59:00 +01:00
|
|
|
typedef Genode::String<Vfs::MAX_PATH_LEN> Path;
|
|
|
|
Path const path = node.attribute_value(attr, Path());
|
2017-01-03 14:33:55 +01:00
|
|
|
|
2019-01-21 15:59:00 +01:00
|
|
|
struct stat out_stat { };
|
|
|
|
if (stat(path.string(), &out_stat) != 0)
|
|
|
|
return;
|
2017-01-03 14:33:55 +01:00
|
|
|
|
2019-01-21 15:59:00 +01:00
|
|
|
Libc::File_descriptor *fd = open(path.string(), flags, libc_fd);
|
|
|
|
if (fd->libc_fd != libc_fd) {
|
|
|
|
Genode::error("could not allocate fd ",libc_fd," for ",path,", "
|
|
|
|
"got fd ",fd->libc_fd);
|
|
|
|
close(fd);
|
|
|
|
return;
|
2018-01-01 05:31:28 +01:00
|
|
|
}
|
2019-01-21 15:59:00 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We need to manually register the path. Normally this is done
|
|
|
|
* by '_open'. But we call the local 'open' function directly
|
|
|
|
* because we want to explicitly specify the libc fd ID.
|
|
|
|
*
|
|
|
|
* We have to allocate the path from the libc (done via 'strdup')
|
|
|
|
* such that the path can be freed when an stdio fd is closed.
|
|
|
|
*/
|
|
|
|
if (fd->fd_path) { Genode::warning("may leak former FD path memory"); }
|
|
|
|
fd->fd_path = strdup(path.string());
|
2016-05-25 15:47:22 +02:00
|
|
|
}
|
|
|
|
|
2017-12-13 00:32:49 +01:00
|
|
|
/**
|
|
|
|
* Sync a handle and propagate errors
|
|
|
|
*/
|
|
|
|
int _vfs_sync(Vfs::Vfs_handle *vfs_handle)
|
2017-08-15 20:51:53 +02:00
|
|
|
{
|
2017-12-13 00:32:49 +01:00
|
|
|
typedef Vfs::File_io_service::Sync_result Result;
|
|
|
|
Result result = Result::SYNC_QUEUED;
|
|
|
|
|
2017-08-15 20:51:53 +02:00
|
|
|
{
|
|
|
|
struct Check : Libc::Suspend_functor
|
|
|
|
{
|
|
|
|
bool retry { false };
|
|
|
|
|
|
|
|
Vfs::Vfs_handle *vfs_handle;
|
|
|
|
|
|
|
|
Check(Vfs::Vfs_handle *vfs_handle)
|
|
|
|
: vfs_handle(vfs_handle) { }
|
|
|
|
|
|
|
|
bool suspend() override
|
|
|
|
{
|
|
|
|
retry = !vfs_handle->fs().queue_sync(vfs_handle);
|
|
|
|
return retry;
|
|
|
|
}
|
|
|
|
} check(vfs_handle);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Cannot call Libc::suspend() immediately, because the Libc kernel
|
|
|
|
* might not be running yet.
|
|
|
|
*/
|
|
|
|
if (!vfs_handle->fs().queue_sync(vfs_handle)) {
|
|
|
|
do {
|
|
|
|
Libc::suspend(check);
|
|
|
|
} while (check.retry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
struct Check : Libc::Suspend_functor
|
|
|
|
{
|
|
|
|
bool retry { false };
|
|
|
|
|
|
|
|
Vfs::Vfs_handle *vfs_handle;
|
2017-12-13 00:32:49 +01:00
|
|
|
Result &result;
|
2017-08-15 20:51:53 +02:00
|
|
|
|
2017-12-13 00:32:49 +01:00
|
|
|
Check(Vfs::Vfs_handle *vfs_handle, Result &result)
|
|
|
|
: vfs_handle(vfs_handle), result(result) { }
|
2017-08-15 20:51:53 +02:00
|
|
|
|
|
|
|
bool suspend() override
|
|
|
|
{
|
2017-12-13 00:32:49 +01:00
|
|
|
result = vfs_handle->fs().complete_sync(vfs_handle);
|
|
|
|
retry = result == Vfs::File_io_service::SYNC_QUEUED;
|
2017-08-15 20:51:53 +02:00
|
|
|
return retry;
|
|
|
|
}
|
2017-12-13 00:32:49 +01:00
|
|
|
} check(vfs_handle, result);
|
2017-08-15 20:51:53 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Cannot call Libc::suspend() immediately, because the Libc kernel
|
|
|
|
* might not be running yet.
|
|
|
|
*/
|
2017-12-13 00:32:49 +01:00
|
|
|
result = vfs_handle->fs().complete_sync(vfs_handle);
|
|
|
|
if (result == Result::SYNC_QUEUED) {
|
2017-08-15 20:51:53 +02:00
|
|
|
do {
|
|
|
|
Libc::suspend(check);
|
|
|
|
} while (check.retry);
|
|
|
|
}
|
|
|
|
}
|
2017-12-13 00:32:49 +01:00
|
|
|
|
|
|
|
return result == Result::SYNC_OK ? 0 : Libc::Errno(EIO);
|
2017-08-15 20:51:53 +02:00
|
|
|
}
|
|
|
|
|
2016-05-25 15:47:22 +02:00
|
|
|
public:
|
|
|
|
|
2019-03-25 15:41:43 +01:00
|
|
|
Vfs_plugin(Libc::Env &env,
|
|
|
|
Genode::Allocator &alloc,
|
|
|
|
Vfs::Io_response_handler &handler)
|
2016-05-25 15:47:22 +02:00
|
|
|
:
|
2019-03-25 15:41:43 +01:00
|
|
|
_alloc(alloc), _root_dir(env.vfs()), _response_handler(handler)
|
2016-05-25 15:47:22 +02:00
|
|
|
{
|
2017-01-03 14:33:55 +01:00
|
|
|
using Genode::Xml_node;
|
|
|
|
|
|
|
|
if (_root_dir.num_dirent("/"))
|
|
|
|
env.config([&] (Xml_node const &top) {
|
2017-04-13 17:53:47 +02:00
|
|
|
|
2019-01-21 15:59:00 +01:00
|
|
|
top.with_sub_node("libc", [&] (Xml_node node) {
|
|
|
|
|
|
|
|
typedef Genode::String<Vfs::MAX_PATH_LEN> Path;
|
|
|
|
|
|
|
|
if (node.has_attribute("cwd"))
|
|
|
|
chdir(node.attribute_value("cwd", Path()).string());
|
2017-04-13 17:53:47 +02:00
|
|
|
|
|
|
|
_open_stdio(node, "stdin", 0, O_RDONLY);
|
|
|
|
_open_stdio(node, "stdout", 1, O_WRONLY);
|
|
|
|
_open_stdio(node, "stderr", 2, O_WRONLY);
|
2019-01-21 15:59:00 +01:00
|
|
|
});
|
2017-01-03 14:33:55 +01:00
|
|
|
});
|
2016-05-25 15:47:22 +02:00
|
|
|
}
|
|
|
|
|
2017-02-01 11:28:15 +01:00
|
|
|
~Vfs_plugin() final { }
|
2016-05-25 15:47:22 +02:00
|
|
|
|
|
|
|
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_readlink(const char *, char *, ::size_t) override { return true; }
|
|
|
|
bool supports_rename(const char *, const char *) override { return true; }
|
|
|
|
bool supports_rmdir(const char *) override { return true; }
|
|
|
|
bool supports_stat(const char *) override { return true; }
|
|
|
|
bool supports_symlink(const char *, const char *) override { return true; }
|
|
|
|
bool supports_unlink(const char *) override { return true; }
|
|
|
|
bool supports_mmap() override { return true; }
|
|
|
|
|
2017-02-01 11:28:15 +01:00
|
|
|
bool supports_select(int nfds,
|
|
|
|
fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
|
|
|
|
struct timeval *timeout) override;
|
|
|
|
|
2016-05-25 15:47:22 +02:00
|
|
|
Libc::File_descriptor *open(const char *, int, int libc_fd);
|
|
|
|
|
|
|
|
Libc::File_descriptor *open(const char *path, int flags) override
|
|
|
|
{
|
|
|
|
return open(path, flags, Libc::ANY_FD);
|
|
|
|
}
|
|
|
|
|
|
|
|
int access(char const *, int) override;
|
|
|
|
int close(Libc::File_descriptor *) override;
|
|
|
|
int dup2(Libc::File_descriptor *, Libc::File_descriptor *) override;
|
|
|
|
int fcntl(Libc::File_descriptor *, int, long) override;
|
|
|
|
int fstat(Libc::File_descriptor *, struct stat *) override;
|
|
|
|
int fstatfs(Libc::File_descriptor *, struct statfs *) override;
|
|
|
|
int fsync(Libc::File_descriptor *fd) override;
|
|
|
|
int ftruncate(Libc::File_descriptor *, ::off_t) override;
|
|
|
|
ssize_t getdirentries(Libc::File_descriptor *, char *, ::size_t , ::off_t *) override;
|
|
|
|
int ioctl(Libc::File_descriptor *, int , char *) override;
|
|
|
|
::off_t lseek(Libc::File_descriptor *fd, ::off_t offset, int whence) override;
|
|
|
|
int mkdir(const char *, mode_t) override;
|
|
|
|
ssize_t read(Libc::File_descriptor *, void *, ::size_t) override;
|
|
|
|
ssize_t readlink(const char *, char *, ::size_t) override;
|
|
|
|
int rename(const char *, const char *) override;
|
|
|
|
int rmdir(const char *) override;
|
|
|
|
int stat(const char *, struct stat *) override;
|
|
|
|
int symlink(const char *, const char *) override;
|
|
|
|
int unlink(const char *) override;
|
|
|
|
ssize_t write(Libc::File_descriptor *, const void *, ::size_t ) override;
|
|
|
|
void *mmap(void *, ::size_t, int, int, Libc::File_descriptor *, ::off_t) override;
|
|
|
|
int munmap(void *, ::size_t) override;
|
2017-02-01 11:28:15 +01:00
|
|
|
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout) override;
|
2016-05-25 15:47:22 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
#endif
|