Module records and aliases
Installation records what a module reports about itself. dpm_install_module opens a module once, writes its version and description to a .meta file in /var/lib/dpm/metadata/, and records the alternate names it declared in modules.aliases beside it. dpm_uninstall_module removes both, leaving the module file in place. dpm_list_modules reads those records and opens no module. A module with no record lists with a version of <uninstalled> and still loads when a caller names it. An unreadable or absent metadata directory costs the listing its detail and costs nothing else. Aliases give a module alternate names, declared through the new dpm_module_aliases contract symbol or added with dpm_add_module_alias. A name is recorded once: one already serving as an alias, or belonging to an installed module, is refused rather than repointed. dpm_require matches a name against the installed modules, then the alias table, then the module path. The metadata directory is a fifth override field and the -M flag, and [modules] metadata in core.conf. The test suite is four binaries covering context, modules, records, and aliases, each a ctest case of its own, alongside the CLI cases.
This commit is contained in:
@@ -96,6 +96,18 @@ typedef struct dpm_module dpm_module;
|
||||
*/
|
||||
typedef struct dpm_cursor dpm_cursor;
|
||||
|
||||
/**
|
||||
* @brief A cursor over recorded module aliases
|
||||
*
|
||||
* Obtained from dpm_list_module_aliases(), advanced with
|
||||
* dpm_alias_cursor_next(), and released with dpm_alias_cursor_free().
|
||||
*
|
||||
* The cursor holds its own copy of what it reports, so it stays readable
|
||||
* after the alias table is changed, and releasing it leaves the table
|
||||
* untouched.
|
||||
*/
|
||||
typedef struct dpm_alias_cursor dpm_alias_cursor;
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Log levels */
|
||||
/* ------------------------------------------------------------------ */
|
||||
@@ -145,6 +157,9 @@ typedef struct dpm_open_overrides {
|
||||
|
||||
/** -1 selects the configured value; otherwise a DPM_LOG_* level. */
|
||||
int log_level;
|
||||
|
||||
/** NULL selects the configured value, then the built-in default. */
|
||||
const char* metadata_dir;
|
||||
} dpm_open_overrides;
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
@@ -168,6 +183,20 @@ typedef struct dpm_module_info {
|
||||
const char* description;
|
||||
} dpm_module_info;
|
||||
|
||||
/**
|
||||
* @brief One recorded alias
|
||||
*
|
||||
* Filled by dpm_alias_cursor_next(). The string pointers remain valid
|
||||
* until the cursor is released.
|
||||
*/
|
||||
typedef struct dpm_alias_info {
|
||||
/** The alternate name. */
|
||||
const char* alias;
|
||||
|
||||
/** The module that name resolves to. */
|
||||
const char* module;
|
||||
} dpm_alias_info;
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Context lifecycle */
|
||||
/* ------------------------------------------------------------------ */
|
||||
@@ -209,10 +238,15 @@ void dpm_close(dpm_ctx* ctx);
|
||||
/**
|
||||
* @brief Loads and returns a validated module
|
||||
*
|
||||
* Resolves the named module in the module path and runs the full
|
||||
* load-time validation sequence if it is not already loaded in this
|
||||
* context. Modules are loaded at most once per context; repeated
|
||||
* calls return the same handle.
|
||||
* Resolves the name to a module file and runs the full load-time
|
||||
* validation sequence if it is not already loaded in this context.
|
||||
* Modules are loaded at most once per context; repeated calls return
|
||||
* the same handle.
|
||||
*
|
||||
* The name is resolved against the installed modules first, then the
|
||||
* alias table, then the module path directly. Reaching the module path
|
||||
* means the module is not installed, which is logged and does not stop
|
||||
* the load.
|
||||
*
|
||||
* Version compatibility is the caller's judgement: read the loaded
|
||||
* module's version with dpm_get_module_info() and decide whether it is
|
||||
@@ -267,18 +301,119 @@ DPM_PUBLIC_ABI_EXPORT
|
||||
int dpm_execute(dpm_ctx* ctx, dpm_module* mod, const char* command,
|
||||
int argc, char** argv);
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Installation */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* @brief Records what a module reports about itself
|
||||
*
|
||||
* Loads the named module once, reads its version, description, and
|
||||
* declared aliases, and writes them into the metadata directory. From
|
||||
* then on dpm_list_modules() reports that module from the record and
|
||||
* opens nothing.
|
||||
*
|
||||
* Each declared alias is added when the name is free. A name already
|
||||
* taken keeps its existing meaning and the installation continues.
|
||||
*
|
||||
* @param ctx The libdpm-core.so context
|
||||
* @param name The module name, its filename minus .so
|
||||
* @return 0 on success, nonzero on failure with the reason available
|
||||
* from dpm_get_last_error()
|
||||
*/
|
||||
DPM_PUBLIC_ABI_EXPORT
|
||||
int dpm_install_module(dpm_ctx* ctx, const char* name);
|
||||
|
||||
/**
|
||||
* @brief Removes a module's record and every alias resolving to it
|
||||
*
|
||||
* Leaves the module file itself in place. The module is thereafter
|
||||
* reported as uninstalled by dpm_list_modules(), and dpm_require() still
|
||||
* loads it by its own name.
|
||||
*
|
||||
* @param ctx The libdpm-core.so context
|
||||
* @param name The module name
|
||||
* @return 0 on success, nonzero on failure with the reason available
|
||||
* from dpm_get_last_error()
|
||||
*/
|
||||
DPM_PUBLIC_ABI_EXPORT
|
||||
int dpm_uninstall_module(dpm_ctx* ctx, const char* name);
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Aliases */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* @brief Records an alternate name for a module
|
||||
*
|
||||
* A name is recorded once. A name already serving as an alias, or
|
||||
* already belonging to an installed module, is refused, so an existing
|
||||
* route to a module is never replaced by a later one. Changing where an
|
||||
* alias points is a removal followed by an addition.
|
||||
*
|
||||
* @param ctx The libdpm-core.so context
|
||||
* @param module The module the name resolves to
|
||||
* @param alias The alternate name
|
||||
* @return 0 on success, nonzero on failure with the reason available
|
||||
* from dpm_get_last_error()
|
||||
*/
|
||||
DPM_PUBLIC_ABI_EXPORT
|
||||
int dpm_add_module_alias(dpm_ctx* ctx, const char* module, const char* alias);
|
||||
|
||||
/**
|
||||
* @brief Removes an alternate name
|
||||
*
|
||||
* @param ctx The libdpm-core.so context
|
||||
* @param alias The alternate name, which identifies the entry on its own
|
||||
* @return 0 on success, nonzero on failure with the reason available
|
||||
* from dpm_get_last_error()
|
||||
*/
|
||||
DPM_PUBLIC_ABI_EXPORT
|
||||
int dpm_remove_module_alias(dpm_ctx* ctx, const char* alias);
|
||||
|
||||
/**
|
||||
* @brief Enumerates recorded aliases
|
||||
*
|
||||
* @param ctx The libdpm-core.so context
|
||||
* @param module NULL for every alias on the system, or a module name for
|
||||
* the aliases resolving to it
|
||||
* @return A cursor over the matching aliases, or NULL on failure
|
||||
*/
|
||||
DPM_PUBLIC_ABI_EXPORT
|
||||
dpm_alias_cursor* dpm_list_module_aliases(dpm_ctx* ctx, const char* module);
|
||||
|
||||
/**
|
||||
* @brief Advances an alias cursor
|
||||
*
|
||||
* @param cur The cursor from dpm_list_module_aliases()
|
||||
* @param out Receives the next alias and the module it resolves to
|
||||
* @return 0 while entries remain; nonzero at end
|
||||
*/
|
||||
DPM_PUBLIC_ABI_EXPORT
|
||||
int dpm_alias_cursor_next(dpm_alias_cursor* cur, dpm_alias_info* out);
|
||||
|
||||
/**
|
||||
* @brief Releases an alias cursor
|
||||
*
|
||||
* @param cur The cursor to release; NULL is a no-op
|
||||
*/
|
||||
DPM_PUBLIC_ABI_EXPORT
|
||||
void dpm_alias_cursor_free(dpm_alias_cursor* cur);
|
||||
|
||||
/* ------------------------------------------------------------------ */
|
||||
/* Enumeration */
|
||||
/* ------------------------------------------------------------------ */
|
||||
|
||||
/**
|
||||
* @brief Enumerates the valid modules in the module path
|
||||
* @brief Enumerates the modules in the module path
|
||||
*
|
||||
* Scans the module path and validates each candidate .so; failures
|
||||
* are logged and excluded from the results.
|
||||
* Reports each installed module from its record, and each module
|
||||
* without one with a version of "<uninstalled>" and an empty
|
||||
* description. No module is opened, so nothing in the module path is
|
||||
* executed to produce a listing.
|
||||
*
|
||||
* @param ctx The libdpm-core.so context
|
||||
* @return A cursor over all valid modules, or NULL on an unreadable
|
||||
* @return A cursor over the modules present, or NULL on an unreadable
|
||||
* module path
|
||||
*/
|
||||
DPM_PUBLIC_ABI_EXPORT
|
||||
@@ -396,10 +531,16 @@ const char* dpm_get_last_error(dpm_ctx* ctx);
|
||||
* int argc, char** argv);
|
||||
* const char* dpm_module_version(void);
|
||||
* const char* dpm_module_description(void);
|
||||
* const char* dpm_module_aliases(void);
|
||||
*
|
||||
* dpm_module_execute is the only entry through which a module performs
|
||||
* work. The other two are what it reports about itself; the library
|
||||
* reads both at load and serves them through dpm_get_module_info.
|
||||
* work. The other three are what it reports about itself; the library
|
||||
* reads them at load, serves the version and description through
|
||||
* dpm_get_module_info, and records the aliases at installation.
|
||||
*
|
||||
* dpm_module_aliases returns a comma-separated list of alternate names
|
||||
* the module answers to, or NULL to declare none. NULL is an answer; the
|
||||
* symbol's absence is a contract violation and the module is refused.
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
Reference in New Issue
Block a user