mirror of
https://github.com/genodelabs/genode.git
synced 2025-01-19 11:16:57 +00:00
libc: configurable initial FDs
The libc already supports the configuration of 'stdin', 'stdout', and 'stderr' using '<libc>' config attributes. This patch equips the libc with the additional ability to pre-initialize any other file descriptor. A file descriptor is configured as follows: <config> ... <libc ...> <fd id="3" path="/dev/log" writeable="yes" readable="no" seek="10"/> ... </libc> </config> Furthermore, this patch moves the FD initialization code from the VFS plugin to the libc kernel initialization because opening the FDs depends on 'malloc' ('strdup'), which should not be used at early 'Libc::Kernel' initialization time. Issue #3478
This commit is contained in:
parent
6e38b53001
commit
65f75589e9
@ -109,6 +109,11 @@ namespace Libc {
|
||||
*/
|
||||
void free(File_descriptor *fdo);
|
||||
|
||||
/**
|
||||
* Prevent the use of the specified file descriptor
|
||||
*/
|
||||
void preserve(int libc_fd);
|
||||
|
||||
File_descriptor *find_by_libc_fd(int libc_fd);
|
||||
};
|
||||
|
||||
|
@ -70,6 +70,13 @@ void File_descriptor_allocator::free(File_descriptor *fdo)
|
||||
}
|
||||
|
||||
|
||||
void File_descriptor_allocator::preserve(int fd)
|
||||
{
|
||||
if (!find_by_libc_fd(fd))
|
||||
alloc(nullptr, nullptr, fd);
|
||||
}
|
||||
|
||||
|
||||
File_descriptor *File_descriptor_allocator::find_by_libc_fd(int libc_fd)
|
||||
{
|
||||
Lock::Guard guard(_lock);
|
||||
|
@ -558,12 +558,16 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
return timeout_ms > 0 ? _main_timeout.duration_left() : 0;
|
||||
}
|
||||
|
||||
void _init_file_descriptors();
|
||||
|
||||
public:
|
||||
|
||||
Kernel(Genode::Env &env, Genode::Allocator &heap)
|
||||
: _env(env), _heap(heap)
|
||||
{
|
||||
_env.ep().register_io_progress_handler(*this);
|
||||
|
||||
_init_file_descriptors();
|
||||
}
|
||||
|
||||
~Kernel() { Genode::error(__PRETTY_FUNCTION__, " should not be executed!"); }
|
||||
@ -818,6 +822,81 @@ struct Libc::Kernel final : Vfs::Io_response_handler,
|
||||
};
|
||||
|
||||
|
||||
void Libc::Kernel::_init_file_descriptors()
|
||||
{
|
||||
auto init_fd = [&] (Genode::Xml_node const &node, char const *attr,
|
||||
int libc_fd, unsigned flags)
|
||||
{
|
||||
if (!node.has_attribute(attr))
|
||||
return;
|
||||
|
||||
typedef Genode::String<Vfs::MAX_PATH_LEN> Path;
|
||||
Path const path = node.attribute_value(attr, Path());
|
||||
|
||||
struct stat out_stat { };
|
||||
if (stat(path.string(), &out_stat) != 0)
|
||||
return;
|
||||
|
||||
Libc::File_descriptor *fd = _vfs.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);
|
||||
_vfs.close(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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());
|
||||
|
||||
::off_t const seek = node.attribute_value("seek", 0ULL);
|
||||
if (seek)
|
||||
_vfs.lseek(fd, seek, SEEK_SET);
|
||||
};
|
||||
|
||||
if (_vfs.root_dir_has_dirents()) {
|
||||
|
||||
Xml_node const node = _libc_env.libc_config();
|
||||
|
||||
typedef Genode::String<Vfs::MAX_PATH_LEN> Path;
|
||||
|
||||
if (node.has_attribute("cwd"))
|
||||
chdir(node.attribute_value("cwd", Path()).string());
|
||||
|
||||
init_fd(node, "stdin", 0, O_RDONLY);
|
||||
init_fd(node, "stdout", 1, O_WRONLY);
|
||||
init_fd(node, "stderr", 2, O_WRONLY);
|
||||
|
||||
node.for_each_sub_node("fd", [&] (Xml_node fd) {
|
||||
|
||||
unsigned const id = fd.attribute_value("id", 0U);
|
||||
|
||||
bool const rd = fd.attribute_value("readable", false);
|
||||
bool const wr = fd.attribute_value("writeable", false);
|
||||
|
||||
unsigned const flags = rd ? (wr ? O_RDWR : O_RDONLY)
|
||||
: (wr ? O_WRONLY : 0);
|
||||
|
||||
if (!fd.has_attribute("path"))
|
||||
warning("Invalid <fd> node, 'path' attribute is missing");
|
||||
|
||||
init_fd(fd, "path", id, flags);
|
||||
});
|
||||
|
||||
/* prevent use of IDs of stdin, stdout, and stderr for other files */
|
||||
for (unsigned fd = 0; fd <= 2; fd++)
|
||||
Libc::file_descriptor_allocator()->preserve(fd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Libc kernel singleton
|
||||
*
|
||||
|
@ -43,41 +43,6 @@ class Libc::Vfs_plugin : public Libc::Plugin
|
||||
Vfs::File_system &_root_dir;
|
||||
Vfs::Io_response_handler &_response_handler;
|
||||
|
||||
void _open_stdio(Genode::Xml_node const &node, char const *attr,
|
||||
int libc_fd, unsigned flags)
|
||||
{
|
||||
if (!node.has_attribute(attr)) {
|
||||
Libc::file_descriptor_allocator()->alloc(nullptr, nullptr, libc_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
typedef Genode::String<Vfs::MAX_PATH_LEN> Path;
|
||||
Path const path = node.attribute_value(attr, Path());
|
||||
|
||||
struct stat out_stat { };
|
||||
if (stat(path.string(), &out_stat) != 0)
|
||||
return;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync a handle and propagate errors
|
||||
*/
|
||||
@ -90,28 +55,12 @@ class Libc::Vfs_plugin : public Libc::Plugin
|
||||
Vfs::Io_response_handler &handler)
|
||||
:
|
||||
_alloc(alloc), _root_dir(env.vfs()), _response_handler(handler)
|
||||
{
|
||||
using Genode::Xml_node;
|
||||
|
||||
if (_root_dir.num_dirent("/"))
|
||||
env.config([&] (Xml_node const &top) {
|
||||
|
||||
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());
|
||||
|
||||
_open_stdio(node, "stdin", 0, O_RDONLY);
|
||||
_open_stdio(node, "stdout", 1, O_WRONLY);
|
||||
_open_stdio(node, "stderr", 2, O_WRONLY);
|
||||
});
|
||||
});
|
||||
}
|
||||
{ }
|
||||
|
||||
~Vfs_plugin() final { }
|
||||
|
||||
bool root_dir_has_dirents() const { return _root_dir.num_dirent("/") > 0; }
|
||||
|
||||
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; }
|
||||
|
Loading…
Reference in New Issue
Block a user