mirror of
https://github.com/matrix-construct/construct
synced 2024-11-25 16:22:35 +01:00
ircd::mods: Toward eliminating boost::filesystem exposure to this unit.
This commit is contained in:
parent
db552e2ec4
commit
e666f72b74
4 changed files with 179 additions and 200 deletions
|
@ -43,16 +43,17 @@ namespace ircd::mods
|
|||
bool unloading(const string_view &name);
|
||||
bool available(const string_view &name);
|
||||
|
||||
// Utils by path
|
||||
bool is_module(const string_view &fullpath);
|
||||
bool is_module(const string_view &fullpath, std::nothrow_t);
|
||||
bool is_module(const string_view &fullpath, std::string &why);
|
||||
|
||||
// returns dir/name of first dir containing 'name' (and this will be
|
||||
// a loadable module). Unlike libltdl, the reason each individual
|
||||
// candidate failed is presented in a vector.
|
||||
std::string search(const string_view &name, std::vector<std::string> &why);
|
||||
std::string search(const string_view &name);
|
||||
std::string fullpath(const string_view &name);
|
||||
|
||||
// Utils by path
|
||||
bool is_module(const string_view &fullpath);
|
||||
bool is_module(const string_view &fullpath, std::nothrow_t);
|
||||
bool is_module(const string_view &fullpath, std::string &why);
|
||||
|
||||
// Potential modules available to load
|
||||
std::forward_list<std::string> available();
|
||||
|
|
|
@ -16,10 +16,9 @@ namespace ircd::mods
|
|||
struct paths extern paths;
|
||||
|
||||
// Platform (.so|.dll) postfixing
|
||||
std::string postfixed(std::string name);
|
||||
std::string postfixed(const string_view &);
|
||||
std::string unpostfixed(std::string name);
|
||||
std::string unpostfixed(const string_view &);
|
||||
std::string postfixed(std::string);
|
||||
std::string unpostfixed(std::string);
|
||||
std::string prefix_if_relative(std::string);
|
||||
}
|
||||
|
||||
struct ircd::mods::paths
|
||||
|
|
333
ircd/mods.cc
333
ircd/mods.cc
|
@ -18,12 +18,6 @@ namespace load_mode = boost::dll::load_mode;
|
|||
#include <ircd/mods/mapi.h> // Module's internal API
|
||||
#include "mods.h"
|
||||
|
||||
const filesystem::path
|
||||
ircd::mods::suffix
|
||||
{
|
||||
boost::dll::shared_library::suffix()
|
||||
};
|
||||
|
||||
ircd::log::log
|
||||
ircd::mods::log
|
||||
{
|
||||
|
@ -72,12 +66,18 @@ ircd::mapi::static_destruction;
|
|||
// mods::mod::mod
|
||||
//
|
||||
|
||||
ircd::mods::mod::mod(const filesystem::path &path,
|
||||
ircd::mods::mod::mod(std::string path,
|
||||
const load_mode::type &mode)
|
||||
try
|
||||
:path{path}
|
||||
,mode{mode}
|
||||
,handle{[this, &path, &mode]
|
||||
:path
|
||||
{
|
||||
std::move(path)
|
||||
}
|
||||
,mode
|
||||
{
|
||||
mode
|
||||
}
|
||||
,handle{[this]
|
||||
{
|
||||
// Can't interrupt this ctx during the dlopen() as long as exceptions
|
||||
// coming out of static inits are trouble (which they are at this time).
|
||||
|
@ -117,7 +117,10 @@ try
|
|||
std::set_terminate(theirs);
|
||||
}};
|
||||
|
||||
return boost::dll::shared_library{path, mode};
|
||||
return boost::dll::shared_library
|
||||
{
|
||||
this->path, this->mode
|
||||
};
|
||||
}()}
|
||||
,_name
|
||||
{
|
||||
|
@ -166,7 +169,7 @@ try
|
|||
{
|
||||
log, "Module '%s' recursively loaded by '%s'",
|
||||
name(),
|
||||
m->path.filename().string()
|
||||
m->name()
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -196,9 +199,6 @@ catch(const boost::system::system_error &e)
|
|||
"undefined symbol: '%s' (%s)", demangled, mangled
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
throw_system_error(e);
|
||||
|
@ -366,15 +366,21 @@ const
|
|||
std::forward_list<std::string>
|
||||
ircd::mods::available()
|
||||
{
|
||||
using filesystem::path;
|
||||
using filesystem::directory_iterator;
|
||||
|
||||
std::forward_list<std::string> ret;
|
||||
for(const auto &dir : paths) try
|
||||
{
|
||||
for(directory_iterator it(dir); it != directory_iterator(); ++it)
|
||||
if(is_module(it->path(), std::nothrow))
|
||||
ret.emplace_front(unpostfixed(relative(it->path(), dir).string()));
|
||||
for(const auto &filepath : fs::ls(dir))
|
||||
{
|
||||
if(!is_module(filepath, std::nothrow))
|
||||
continue;
|
||||
|
||||
std::string relpath
|
||||
{
|
||||
fs::relative(fs::path_scratch, dir, filepath)
|
||||
};
|
||||
|
||||
ret.emplace_front(unpostfixed(std::move(relpath)));
|
||||
}
|
||||
}
|
||||
catch(const filesystem::filesystem_error &e)
|
||||
{
|
||||
|
@ -391,30 +397,36 @@ ircd::mods::available()
|
|||
return ret;
|
||||
}
|
||||
|
||||
filesystem::path
|
||||
std::string
|
||||
ircd::mods::fullpath(const string_view &name)
|
||||
{
|
||||
std::vector<std::string> why;
|
||||
const filesystem::path path(search(name, why));
|
||||
if(path.empty())
|
||||
const auto path
|
||||
{
|
||||
for(const auto &str : why)
|
||||
log::error
|
||||
{
|
||||
log, "candidate for module '%s' failed: %s",
|
||||
name,
|
||||
str
|
||||
};
|
||||
search(name, why)
|
||||
};
|
||||
|
||||
throw error
|
||||
if(likely(!path.empty()))
|
||||
return path;
|
||||
|
||||
for(const auto &str : why)
|
||||
log::error
|
||||
{
|
||||
"No valid module by name `%s'", name
|
||||
log, "candidate for module '%s' failed: %s",
|
||||
name,
|
||||
str
|
||||
};
|
||||
}
|
||||
|
||||
return path;
|
||||
throw error
|
||||
{
|
||||
"No valid module by name `%s'", name
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// search()
|
||||
//
|
||||
|
||||
std::string
|
||||
ircd::mods::search(const string_view &name)
|
||||
{
|
||||
|
@ -426,14 +438,12 @@ std::string
|
|||
ircd::mods::search(const string_view &name,
|
||||
std::vector<std::string> &why)
|
||||
{
|
||||
using filesystem::path;
|
||||
|
||||
const path path
|
||||
const std::string path
|
||||
{
|
||||
postfixed(name)
|
||||
};
|
||||
|
||||
if(!path.is_relative())
|
||||
if(!fs::is_relative(path))
|
||||
{
|
||||
why.resize(why.size() + 1);
|
||||
return is_module(path, why.back())?
|
||||
|
@ -442,36 +452,30 @@ ircd::mods::search(const string_view &name,
|
|||
}
|
||||
else for(const auto &dir : paths)
|
||||
{
|
||||
const string_view parts[2]
|
||||
{
|
||||
dir, path
|
||||
};
|
||||
|
||||
const auto full
|
||||
{
|
||||
fs::path_string(parts)
|
||||
};
|
||||
|
||||
why.resize(why.size() + 1);
|
||||
if(is_module(dir/path, why.back()))
|
||||
return (dir/path).string();
|
||||
if(is_module(full, why.back()))
|
||||
return full;
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::mods::is_module(const string_view &fullpath)
|
||||
{
|
||||
return is_module(filesystem::path(std::string{fullpath}));
|
||||
}
|
||||
//
|
||||
// is_module
|
||||
//
|
||||
|
||||
bool
|
||||
ircd::mods::is_module(const string_view &fullpath,
|
||||
std::nothrow_t)
|
||||
{
|
||||
return is_module(filesystem::path(std::string{fullpath}), std::nothrow);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::mods::is_module(const string_view &fullpath,
|
||||
std::string &why)
|
||||
{
|
||||
return is_module(filesystem::path(std::string{fullpath}), why);
|
||||
}
|
||||
|
||||
bool
|
||||
ircd::mods::is_module(const filesystem::path &path,
|
||||
ircd::mods::is_module(const string_view &path,
|
||||
std::nothrow_t)
|
||||
try
|
||||
{
|
||||
|
@ -483,7 +487,7 @@ catch(const std::exception &e)
|
|||
}
|
||||
|
||||
bool
|
||||
ircd::mods::is_module(const filesystem::path &path,
|
||||
ircd::mods::is_module(const string_view &path,
|
||||
std::string &why)
|
||||
try
|
||||
{
|
||||
|
@ -496,20 +500,36 @@ catch(const std::exception &e)
|
|||
}
|
||||
|
||||
bool
|
||||
ircd::mods::is_module(const filesystem::path &path)
|
||||
ircd::mods::is_module(const string_view &path)
|
||||
{
|
||||
const auto syms(symbols(path));
|
||||
const auto &header_name(mapi::header_symbol_name);
|
||||
const auto it(std::find(begin(syms), end(syms), header_name));
|
||||
static const auto &header_name
|
||||
{
|
||||
mapi::header_symbol_name
|
||||
};
|
||||
|
||||
const auto syms
|
||||
{
|
||||
symbols(path)
|
||||
};
|
||||
|
||||
const auto it
|
||||
{
|
||||
std::find(begin(syms), end(syms), header_name)
|
||||
};
|
||||
|
||||
if(it == end(syms))
|
||||
throw error
|
||||
{
|
||||
"`%s': has no MAPI header (%s)", path.string(), header_name
|
||||
"`%s': has no MAPI header (%s)", path, header_name
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// utils by name
|
||||
//
|
||||
|
||||
bool
|
||||
ircd::mods::available(const string_view &name)
|
||||
{
|
||||
|
@ -549,6 +569,10 @@ ircd::mods::loaded(const string_view &name)
|
|||
return mod::loaded.count(name);
|
||||
}
|
||||
|
||||
//
|
||||
// utils by mod reference
|
||||
//
|
||||
|
||||
template<> uint8_t *
|
||||
ircd::mods::ptr<uint8_t>(mod &mod,
|
||||
const string_view &sym)
|
||||
|
@ -666,6 +690,12 @@ ircd::mods::module::module(const string_view &name)
|
|||
try
|
||||
:std::shared_ptr<mod>{[&name]
|
||||
{
|
||||
static const load_mode::type flags
|
||||
{
|
||||
load_mode::rtld_local |
|
||||
load_mode::rtld_now
|
||||
};
|
||||
|
||||
// Search for loaded module and increment the reference counter for this handle if loaded.
|
||||
auto it(mod::loaded.find(name));
|
||||
if(it != end(mod::loaded))
|
||||
|
@ -674,23 +704,21 @@ try
|
|||
return shared_from(mod);
|
||||
}
|
||||
|
||||
static const load_mode::type flags
|
||||
auto path
|
||||
{
|
||||
load_mode::rtld_local |
|
||||
load_mode::rtld_now
|
||||
fullpath(name)
|
||||
};
|
||||
|
||||
const auto path(fullpath(name));
|
||||
log::debug
|
||||
{
|
||||
log, "Attempting to load '%s' @ `%s'",
|
||||
name,
|
||||
path.string()
|
||||
path
|
||||
};
|
||||
|
||||
const auto ret
|
||||
{
|
||||
std::make_shared<mod>(path, flags)
|
||||
std::make_shared<mod>(std::move(path), flags)
|
||||
};
|
||||
|
||||
// Call the user-supplied init function well after fully loading and
|
||||
|
@ -757,8 +785,12 @@ const
|
|||
std::vector<std::string>
|
||||
ircd::mods::find_symbol(const string_view &symbol)
|
||||
{
|
||||
const auto av
|
||||
{
|
||||
available()
|
||||
};
|
||||
|
||||
std::vector<std::string> ret;
|
||||
const auto av(available());
|
||||
std::copy_if(begin(av), end(av), std::back_inserter(ret), [&symbol]
|
||||
(const auto &name)
|
||||
{
|
||||
|
@ -772,35 +804,30 @@ bool
|
|||
ircd::mods::has_symbol(const string_view &name,
|
||||
const string_view &symbol)
|
||||
{
|
||||
const auto path(fullpath(name));
|
||||
const auto path
|
||||
{
|
||||
fullpath(name)
|
||||
};
|
||||
|
||||
if(path.empty())
|
||||
return false;
|
||||
|
||||
const auto syms(symbols(path));
|
||||
const auto syms
|
||||
{
|
||||
symbols(path)
|
||||
};
|
||||
|
||||
return std::find(begin(syms), end(syms), symbol) != end(syms);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string>
|
||||
ircd::mods::mangles(const string_view &fullpath)
|
||||
{
|
||||
return mangles(filesystem::path(std::string{fullpath}));
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string>
|
||||
ircd::mods::mangles(const string_view &fullpath,
|
||||
const string_view §ion)
|
||||
{
|
||||
return mangles(filesystem::path(std::string{fullpath}), section);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string>
|
||||
ircd::mods::mangles(const filesystem::path &path)
|
||||
ircd::mods::mangles(const string_view &path)
|
||||
{
|
||||
return mangles(mods::symbols(path));
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::string>
|
||||
ircd::mods::mangles(const filesystem::path &path,
|
||||
ircd::mods::mangles(const string_view &path,
|
||||
const string_view §ion)
|
||||
{
|
||||
return mangles(mods::symbols(path, section));
|
||||
|
@ -823,20 +850,7 @@ ircd::mods::mangles(const std::vector<std::string> &symbols)
|
|||
}
|
||||
|
||||
std::vector<std::string>
|
||||
ircd::mods::symbols(const string_view &fullpath)
|
||||
{
|
||||
return symbols(filesystem::path(std::string{fullpath}));
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
ircd::mods::symbols(const string_view &fullpath,
|
||||
const string_view §ion)
|
||||
{
|
||||
return symbols(filesystem::path(std::string{fullpath}), std::string{section});
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
ircd::mods::symbols(const filesystem::path &path)
|
||||
ircd::mods::symbols(const string_view &path)
|
||||
{
|
||||
return info<std::vector<std::string>>(path, []
|
||||
(boost::dll::library_info &info)
|
||||
|
@ -846,7 +860,7 @@ ircd::mods::symbols(const filesystem::path &path)
|
|||
}
|
||||
|
||||
std::vector<std::string>
|
||||
ircd::mods::symbols(const filesystem::path &path,
|
||||
ircd::mods::symbols(const string_view &path,
|
||||
const string_view §ion)
|
||||
{
|
||||
return info<std::vector<std::string>>(path, [§ion]
|
||||
|
@ -857,13 +871,7 @@ ircd::mods::symbols(const filesystem::path &path,
|
|||
}
|
||||
|
||||
std::vector<std::string>
|
||||
ircd::mods::sections(const string_view &fullpath)
|
||||
{
|
||||
return sections(filesystem::path(std::string{fullpath}));
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
ircd::mods::sections(const filesystem::path &path)
|
||||
ircd::mods::sections(const string_view &path)
|
||||
{
|
||||
return info<std::vector<std::string>>(path, []
|
||||
(boost::dll::library_info &info)
|
||||
|
@ -875,18 +883,22 @@ ircd::mods::sections(const filesystem::path &path)
|
|||
template<class R,
|
||||
class F>
|
||||
R
|
||||
ircd::mods::info(const filesystem::path &path,
|
||||
ircd::mods::info(const string_view &path,
|
||||
F&& closure)
|
||||
try
|
||||
{
|
||||
boost::dll::library_info info(path);
|
||||
boost::dll::library_info info
|
||||
{
|
||||
fs::_path(path)
|
||||
};
|
||||
|
||||
return closure(info);
|
||||
}
|
||||
catch(const filesystem::filesystem_error &e)
|
||||
{
|
||||
throw fs::error
|
||||
{
|
||||
e, "%s", path.string()
|
||||
e, "%s", path
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -895,68 +907,55 @@ catch(const filesystem::filesystem_error &e)
|
|||
// mods/paths.h
|
||||
//
|
||||
|
||||
namespace ircd::mods
|
||||
{
|
||||
extern const filesystem::path modroot;
|
||||
}
|
||||
|
||||
decltype(ircd::mods::modroot)
|
||||
ircd::mods::modroot
|
||||
decltype(ircd::mods::prefix)
|
||||
ircd::mods::prefix
|
||||
{
|
||||
fs::path(fs::MODULES)
|
||||
};
|
||||
|
||||
decltype(ircd::mods::suffix)
|
||||
ircd::mods::suffix
|
||||
{
|
||||
boost::dll::shared_library::suffix().string()
|
||||
};
|
||||
|
||||
decltype(ircd::mods::paths)
|
||||
ircd::mods::paths
|
||||
{};
|
||||
|
||||
//
|
||||
// util
|
||||
//
|
||||
|
||||
std::string
|
||||
ircd::mods::unpostfixed(const string_view &name)
|
||||
ircd::mods::unpostfixed(std::string path)
|
||||
{
|
||||
return unpostfixed(std::string{name});
|
||||
if(fs::extension(fs::path_scratch, path) == suffix)
|
||||
return fs::extension(fs::path_scratch, path, string_view{});
|
||||
|
||||
return std::move(path);
|
||||
}
|
||||
|
||||
std::string
|
||||
ircd::mods::unpostfixed(std::string name)
|
||||
ircd::mods::postfixed(std::string path)
|
||||
{
|
||||
return unpostfixed(filesystem::path(std::move(name))).string();
|
||||
return fs::extension(fs::path_scratch, path) != suffix?
|
||||
path + suffix:
|
||||
path;
|
||||
}
|
||||
|
||||
std::string
|
||||
ircd::mods::postfixed(const string_view &name)
|
||||
ircd::mods::prefix_if_relative(std::string path)
|
||||
{
|
||||
return postfixed(std::string{name});
|
||||
}
|
||||
if(!fs::is_relative(path))
|
||||
return std::move(path);
|
||||
|
||||
std::string
|
||||
ircd::mods::postfixed(std::string name)
|
||||
{
|
||||
return postfixed(filesystem::path(std::move(name))).string();
|
||||
}
|
||||
const string_view parts[2]
|
||||
{
|
||||
prefix, path
|
||||
};
|
||||
|
||||
filesystem::path
|
||||
ircd::mods::unpostfixed(const filesystem::path &path)
|
||||
{
|
||||
if(extension(path) != suffix)
|
||||
return path;
|
||||
|
||||
return filesystem::path(path).replace_extension();
|
||||
}
|
||||
|
||||
filesystem::path
|
||||
ircd::mods::postfixed(const filesystem::path &path)
|
||||
{
|
||||
if(extension(path) == suffix)
|
||||
return path;
|
||||
|
||||
filesystem::path ret(path);
|
||||
return ret += suffix;
|
||||
}
|
||||
|
||||
filesystem::path
|
||||
ircd::mods::prefix_if_relative(const filesystem::path &path)
|
||||
{
|
||||
return path.is_relative()? (modroot / path) : path;
|
||||
return fs::path_string(parts);
|
||||
}
|
||||
|
||||
//
|
||||
|
@ -966,7 +965,7 @@ ircd::mods::prefix_if_relative(const filesystem::path &path)
|
|||
ircd::mods::paths::paths()
|
||||
:std::vector<std::string>
|
||||
{{
|
||||
modroot.string()
|
||||
mods::prefix
|
||||
}}
|
||||
{
|
||||
}
|
||||
|
@ -974,28 +973,26 @@ ircd::mods::paths::paths()
|
|||
bool
|
||||
ircd::mods::paths::add(const string_view &dir)
|
||||
{
|
||||
using filesystem::path;
|
||||
|
||||
const path path
|
||||
const auto path
|
||||
{
|
||||
prefix_if_relative(std::string{dir})
|
||||
prefix_if_relative(dir)
|
||||
};
|
||||
|
||||
if(!exists(path))
|
||||
if(!fs::exists(path))
|
||||
throw fs::error
|
||||
{
|
||||
make_error_code(std::errc::no_such_file_or_directory),
|
||||
"path `%s' (%s) does not exist",
|
||||
dir,
|
||||
path.string()
|
||||
path
|
||||
};
|
||||
|
||||
if(!is_directory(path))
|
||||
if(!fs::is_dir(path))
|
||||
throw fs::error
|
||||
{
|
||||
"path `%s' (%s) is not a directory",
|
||||
dir,
|
||||
path.string()
|
||||
path
|
||||
};
|
||||
|
||||
if(added(dir))
|
||||
|
@ -1025,7 +1022,7 @@ catch(const std::exception &e)
|
|||
bool
|
||||
ircd::mods::paths::del(const string_view &dir)
|
||||
{
|
||||
std::remove(begin(), end(), prefix_if_relative(std::string{dir}).string());
|
||||
std::remove(begin(), end(), prefix_if_relative(dir));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
28
ircd/mods.h
28
ircd/mods.h
|
@ -10,27 +10,10 @@
|
|||
|
||||
namespace ircd::mods
|
||||
{
|
||||
extern const filesystem::path suffix;
|
||||
extern const std::string prefix;
|
||||
extern const std::string suffix;
|
||||
|
||||
filesystem::path prefix_if_relative(const filesystem::path &path);
|
||||
filesystem::path postfixed(const filesystem::path &path);
|
||||
filesystem::path unpostfixed(const filesystem::path &path);
|
||||
|
||||
template<class R, class F> R info(const filesystem::path &, F&& closure);
|
||||
std::vector<std::string> sections(const filesystem::path &path);
|
||||
std::vector<std::string> symbols(const filesystem::path &path);
|
||||
std::vector<std::string> symbols(const filesystem::path &path, const string_view §ion);
|
||||
std::unordered_map<std::string, std::string> mangles(const std::vector<std::string> &);
|
||||
std::unordered_map<std::string, std::string> mangles(const filesystem::path &path);
|
||||
std::unordered_map<std::string, std::string> mangles(const filesystem::path &path, const string_view §ion);
|
||||
|
||||
// Get the full path of a [valid] available module by name
|
||||
filesystem::path fullpath(const string_view &name);
|
||||
|
||||
// Checks if loadable module containing a mapi header (does not verify the magic)
|
||||
bool is_module(const filesystem::path &);
|
||||
bool is_module(const filesystem::path &, std::string &why);
|
||||
bool is_module(const filesystem::path &, std::nothrow_t);
|
||||
template<class R, class F> R info(const string_view &, F&& closure);
|
||||
}
|
||||
|
||||
/// Internal module representation
|
||||
|
@ -41,7 +24,7 @@ struct ircd::mods::mod
|
|||
static std::forward_list<mod *> unloading; // dlclose() is not recursive but we have this
|
||||
static std::map<string_view, mod *, std::less<>> loaded;
|
||||
|
||||
filesystem::path path;
|
||||
std::string path;
|
||||
load_mode::type mode;
|
||||
std::deque<mod *> children;
|
||||
boost::dll::shared_library handle;
|
||||
|
@ -61,8 +44,7 @@ struct ircd::mods::mod
|
|||
|
||||
bool unload();
|
||||
|
||||
mod(const filesystem::path &,
|
||||
const load_mode::type & = load_mode::rtld_local | load_mode::rtld_now);
|
||||
explicit mod(std::string path, const load_mode::type &);
|
||||
|
||||
mod(mod &&) = delete;
|
||||
mod(const mod &) = delete;
|
||||
|
|
Loading…
Reference in a new issue