One way to record an error, and a name that reads as a query
dpm_module_info_of becomes dpm_get_module_info, joining the other two readers on the context in stating that a call fetches a value. Recording an error had two entry points doing the same write: the exported dpm_set_last_error and an internal dpm_core::set_last_error taking a std::string. The internal one is gone and the loader calls the exported function, so a reason reaches the context by one path whether a module or the library records it.
This commit is contained in:
@@ -56,11 +56,11 @@ dpm_module* mod = dpm_require(ctx, "mymodule");
|
|||||||
|
|
||||||
libdpm-core.so validates the module completely at load; a handle is returned only for a fully valid module. NULL means the module is absent or invalid — `dpm_get_last_error`(ctx) carries the precise reason. Modules load at most once per context; repeated calls return the same handle.
|
libdpm-core.so validates the module completely at load; a handle is returned only for a fully valid module. NULL means the module is absent or invalid — `dpm_get_last_error`(ctx) carries the precise reason. Modules load at most once per context; repeated calls return the same handle.
|
||||||
|
|
||||||
`dpm_module_info_of` reports what the library saw in the loaded module:
|
`dpm_get_module_info` reports what the library saw in the loaded module:
|
||||||
|
|
||||||
```
|
```
|
||||||
dpm_module_info info;
|
dpm_module_info info;
|
||||||
dpm_module_info_of(ctx, mod, &info);
|
dpm_get_module_info(ctx, mod, &info);
|
||||||
```
|
```
|
||||||
|
|
||||||
`info` carries `name`, `version`, and `description`.
|
`info` carries `name`, `version`, and `description`.
|
||||||
@@ -91,7 +91,7 @@ The cursor covers every valid module in the module path; invalid candidates are
|
|||||||
## Services
|
## Services
|
||||||
|
|
||||||
- `dpm_core_version`()** — the library version; callable without a context.
|
- `dpm_core_version`()** — the library version; callable without a context.
|
||||||
- `dpm_module_info_of`(ctx, mod, out)** — the name, version, and description read from a loaded module.
|
- `dpm_get_module_info`(ctx, mod, out)** — the name, version, and description read from a loaded module.
|
||||||
- `dpm_config_get`(ctx, module, section, key)** — a value from a module's configuration namespace, or NULL if unset.
|
- `dpm_config_get`(ctx, module, section, key)** — a value from a module's configuration namespace, or NULL if unset.
|
||||||
- `dpm_log`(ctx, level, message)** — writes to the context's configured log targets; levels are `DPM_LOG_FATAL` through `DPM_LOG_DEBUG`.
|
- `dpm_log`(ctx, level, message)** — writes to the context's configured log targets; levels are `DPM_LOG_FATAL` through `DPM_LOG_DEBUG`.
|
||||||
- `dpm_get_resolved_module_path`(ctx)** — the resolved module directory.
|
- `dpm_get_resolved_module_path`(ctx)** — the resolved module directory.
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ Releases the context: unloads every module handle it issued, closes log targets,
|
|||||||
`dpm_module* dpm_require(dpm_ctx* ctx, const char* name)`
|
`dpm_module* dpm_require(dpm_ctx* ctx, const char* name)`
|
||||||
Resolves the module `name` in the module path and runs the full load-time validation sequence (see Load-Time Enforcement) if the module is not already loaded in this context. On success returns a module handle owned by the context (repeated calls return the same handle — modules are loaded at most once per context). On failure returns NULL and records the precise reason: not found, or validation step failed with the step and detail. No version criterion is applied here; compatibility is the caller's to determine from the reported version.
|
Resolves the module `name` in the module path and runs the full load-time validation sequence (see Load-Time Enforcement) if the module is not already loaded in this context. On success returns a module handle owned by the context (repeated calls return the same handle — modules are loaded at most once per context). On failure returns NULL and records the precise reason: not found, or validation step failed with the step and detail. No version criterion is applied here; compatibility is the caller's to determine from the reported version.
|
||||||
|
|
||||||
`int dpm_module_info_of(dpm_ctx* ctx, dpm_module* mod, dpm_module_info* out)`
|
`int dpm_get_module_info(dpm_ctx* ctx, dpm_module* mod, dpm_module_info* out)`
|
||||||
Fills `out` with the loaded module's name, version, and description exactly as they were read at load (string pointers valid until context close). This is how a consumer obtains the version it will judge. The library attaches no meaning to the values. Returns 0 on success, nonzero if the module cannot be reported on.
|
Fills `out` with the loaded module's name, version, and description exactly as they were read at load (string pointers valid until context close). This is how a consumer obtains the version it will judge. The library attaches no meaning to the values. Returns 0 on success, nonzero if the module cannot be reported on.
|
||||||
|
|
||||||
`int dpm_execute(dpm_ctx* ctx, dpm_module* mod, const char* command, int argc, char** argv)`
|
`int dpm_execute(dpm_ctx* ctx, dpm_module* mod, const char* command, int argc, char** argv)`
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ The `ctx` is the one handed to your entry point. Nothing else is needed to reach
|
|||||||
|
|
||||||
**Never link, include, or hardcode anything belonging to a peer.** No peer headers, no shared types, no peer symbols. Modules are loaded with `RTLD_LOCAL`, so a peer's symbols are not reachable from your module even if you tried — libdpm-core.so is the only path, and the only knowledge you hold about a peer is its name and the commands it documents.
|
**Never link, include, or hardcode anything belonging to a peer.** No peer headers, no shared types, no peer symbols. Modules are loaded with `RTLD_LOCAL`, so a peer's symbols are not reachable from your module even if you tried — libdpm-core.so is the only path, and the only knowledge you hold about a peer is its name and the commands it documents.
|
||||||
|
|
||||||
A module that depends on a peer is the party that judges the peer's version. Require it, read its reported version with `dpm_module_info_of`, and decide whether it is suitable for the commands you intend to issue. libdpm-core.so reports; it does not rule.
|
A module that depends on a peer is the party that judges the peer's version. Require it, read its reported version with `dpm_get_module_info`, and decide whether it is suitable for the commands you intend to issue. libdpm-core.so reports; it does not rule.
|
||||||
|
|
||||||
## Validation at Load
|
## Validation at Load
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ The context owns everything it hands out. Every string a caller receives stays v
|
|||||||
|
|
||||||
**Acquiring a module.** `dpm_require` resolves a module by name, validates it completely, and returns a handle — or returns NULL, with `dpm_get_last_error` carrying the precise reason. Modules load at most once per context, and repeated calls return the same handle.
|
**Acquiring a module.** `dpm_require` resolves a module by name, validates it completely, and returns a handle — or returns NULL, with `dpm_get_last_error` carrying the precise reason. Modules load at most once per context, and repeated calls return the same handle.
|
||||||
|
|
||||||
**Reading what the library saw.** `dpm_module_info_of` fills in a module's name, version, and description. Those values are reported, and no conclusion is drawn from them.
|
**Reading what the library saw.** `dpm_get_module_info` fills in a module's name, version, and description. Those values are reported, and no conclusion is drawn from them.
|
||||||
|
|
||||||
**Calling into a module.** `dpm_execute` passes a command name and an argument vector to the module's entry point and returns its result. This is the only path into module code, and it is the same one the `dpm` binary takes.
|
**Calling into a module.** `dpm_execute` passes a command name and an argument vector to the module's entry point and returns its result. This is the only path into module code, and it is the same one the `dpm` binary takes.
|
||||||
|
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ typedef struct dpm_open_overrides {
|
|||||||
/**
|
/**
|
||||||
* @brief What the library read from a module at load
|
* @brief What the library read from a module at load
|
||||||
*
|
*
|
||||||
* Filled by dpm_module_info_of() and by dpm_cursor_next(). The string
|
* Filled by dpm_get_module_info() and by dpm_cursor_next(). The string
|
||||||
* pointers remain valid until the context is closed.
|
* pointers remain valid until the context is closed.
|
||||||
*/
|
*/
|
||||||
typedef struct dpm_module_info {
|
typedef struct dpm_module_info {
|
||||||
@@ -215,7 +215,7 @@ void dpm_close(dpm_ctx* ctx);
|
|||||||
* calls return the same handle.
|
* calls return the same handle.
|
||||||
*
|
*
|
||||||
* Version compatibility is the caller's judgement: read the loaded
|
* Version compatibility is the caller's judgement: read the loaded
|
||||||
* module's version with dpm_module_info_of() and decide whether it is
|
* module's version with dpm_get_module_info() and decide whether it is
|
||||||
* acceptable.
|
* acceptable.
|
||||||
*
|
*
|
||||||
* @param ctx The libdpm-core.so context
|
* @param ctx The libdpm-core.so context
|
||||||
@@ -240,7 +240,7 @@ dpm_module* dpm_require(dpm_ctx* ctx, const char* name);
|
|||||||
* @return 0 on success, nonzero if the module cannot be reported on
|
* @return 0 on success, nonzero if the module cannot be reported on
|
||||||
*/
|
*/
|
||||||
DPM_PUBLIC_ABI_EXPORT
|
DPM_PUBLIC_ABI_EXPORT
|
||||||
int dpm_module_info_of(dpm_ctx* ctx, dpm_module* mod,
|
int dpm_get_module_info(dpm_ctx* ctx, dpm_module* mod,
|
||||||
dpm_module_info* out);
|
dpm_module_info* out);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -399,7 +399,7 @@ const char* dpm_get_last_error(dpm_ctx* ctx);
|
|||||||
*
|
*
|
||||||
* dpm_module_execute is the only entry through which a module performs
|
* dpm_module_execute is the only entry through which a module performs
|
||||||
* work. The other two are what it reports about itself; the library
|
* work. The other two are what it reports about itself; the library
|
||||||
* reads both at load and serves them through dpm_module_info_of.
|
* reads both at load and serves them through dpm_get_module_info.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ struct dpm_ctx {
|
|||||||
* @brief Internal implementation of libdpm-core.so
|
* @brief Internal implementation of libdpm-core.so
|
||||||
*
|
*
|
||||||
* Holds what the library's translation units share with each other and
|
* Holds what the library's translation units share with each other and
|
||||||
* with nothing else: the loader, the configuration reader, the error
|
* with nothing else: the loader, the configuration reader, the value
|
||||||
* recorder, and the version parser. It is declared in include/internal/,
|
* sanitizers, and the version parser. It is declared in include/internal/,
|
||||||
* which is never installed, so a consumer or a module cannot name any of
|
* which is never installed, so a consumer or a module cannot name any of
|
||||||
* it.
|
* it.
|
||||||
*
|
*
|
||||||
@@ -82,12 +82,3 @@ struct dpm_ctx {
|
|||||||
* unnamed namespace instead, which gives them internal linkage and keeps
|
* unnamed namespace instead, which gives them internal linkage and keeps
|
||||||
* them from colliding across files.
|
* them from colliding across files.
|
||||||
*/
|
*/
|
||||||
namespace dpm_core {
|
|
||||||
/**
|
|
||||||
* @brief Records a failure reason on the context
|
|
||||||
*
|
|
||||||
* @param ctx The libdpm-core.so context; NULL is a no-op
|
|
||||||
* @param msg The failure description
|
|
||||||
*/
|
|
||||||
void set_last_error(dpm_ctx* ctx, const std::string& msg);
|
|
||||||
} // namespace dpm_core
|
|
||||||
|
|||||||
@@ -49,20 +49,6 @@ namespace {
|
|||||||
const char* DEFAULT_LOG_FILE = "/var/log/dpm/dpm.log";
|
const char* DEFAULT_LOG_FILE = "/var/log/dpm/dpm.log";
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace dpm_core {
|
|
||||||
/**
|
|
||||||
* @brief Records a failure reason on the context
|
|
||||||
*
|
|
||||||
* Overwrites whatever reason was recorded previously, so the context
|
|
||||||
* carries the most recent failure and nothing older.
|
|
||||||
*/
|
|
||||||
void set_last_error(dpm_ctx* ctx, const std::string& msg) {
|
|
||||||
if (ctx) {
|
|
||||||
ctx->last_error = msg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace dpm_core
|
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
/**
|
/**
|
||||||
* @brief Creates a context
|
* @brief Creates a context
|
||||||
|
|||||||
@@ -213,8 +213,8 @@ extern "C" {
|
|||||||
std::string reason;
|
std::string reason;
|
||||||
auto loaded = dpm_core::validate_and_load(ctx, name, reason);
|
auto loaded = dpm_core::validate_and_load(ctx, name, reason);
|
||||||
if (!loaded) {
|
if (!loaded) {
|
||||||
dpm_core::set_last_error(ctx, std::string("module '") + name +
|
dpm_set_last_error(ctx, (std::string("module '") + name +
|
||||||
"': " + reason);
|
"': " + reason).c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +231,7 @@ extern "C" {
|
|||||||
* The strings point into the module's registry entry, so they remain
|
* The strings point into the module's registry entry, so they remain
|
||||||
* valid as long as the context holds the module.
|
* valid as long as the context holds the module.
|
||||||
*/
|
*/
|
||||||
int dpm_module_info_of(dpm_ctx* ctx, dpm_module* mod, dpm_module_info* out) {
|
int dpm_get_module_info(dpm_ctx* ctx, dpm_module* mod, dpm_module_info* out) {
|
||||||
if (!ctx || !mod || !out) {
|
if (!ctx || !mod || !out) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -275,8 +275,8 @@ extern "C" {
|
|||||||
|
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
if (!fs::is_directory(ctx->module_path, ec)) {
|
if (!fs::is_directory(ctx->module_path, ec)) {
|
||||||
dpm_core::set_last_error(ctx, "module path is not a readable directory: " +
|
dpm_set_last_error(ctx, ("module path is not a readable directory: " +
|
||||||
ctx->module_path);
|
ctx->module_path).c_str());
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -117,13 +117,13 @@ int main(void) {
|
|||||||
|
|
||||||
/* libdpm-core reports what it saw; the caller judges compatibility */
|
/* libdpm-core reports what it saw; the caller judges compatibility */
|
||||||
dpm_module_info seen;
|
dpm_module_info seen;
|
||||||
CHECK(dpm_module_info_of(ctx, good, &seen) == 0);
|
CHECK(dpm_get_module_info(ctx, good, &seen) == 0);
|
||||||
CHECK(std::strcmp(seen.name, "good") == 0);
|
CHECK(std::strcmp(seen.name, "good") == 0);
|
||||||
CHECK(std::strcmp(seen.version, "1.2.3") == 0);
|
CHECK(std::strcmp(seen.version, "1.2.3") == 0);
|
||||||
CHECK(seen.description != nullptr && *seen.description);
|
CHECK(seen.description != nullptr && *seen.description);
|
||||||
|
|
||||||
CHECK(dpm_module_info_of(ctx, nullptr, &seen) != 0);
|
CHECK(dpm_get_module_info(ctx, nullptr, &seen) != 0);
|
||||||
CHECK(dpm_module_info_of(ctx, good, nullptr) != 0);
|
CHECK(dpm_get_module_info(ctx, good, nullptr) != 0);
|
||||||
|
|
||||||
/* dispatch: the module's return value comes back verbatim, so a
|
/* dispatch: the module's return value comes back verbatim, so a
|
||||||
command round trip is observable without any compile-time
|
command round trip is observable without any compile-time
|
||||||
|
|||||||
Reference in New Issue
Block a user