CP_C_API void cp_unregister_ploader(cp_context_t *ctx, cp_plugin_loader_t *loader) { hnode_t *hnode; CHECK_NOT_NULL(ctx); CHECK_NOT_NULL(loader); cpi_lock_context(ctx); cpi_check_invocation(ctx, CPI_CF_ANY, __func__); hnode = hash_lookup(ctx->env->loaders_to_plugins, loader); if (hnode != NULL) { hash_t *loader_plugins = hnode_get(hnode); // Uninstall all plug-ins loaded by the loader while (!hash_isempty(loader_plugins)) { hscan_t hscan; hnode_t *hnode2; cp_status_t status; hash_scan_begin(&hscan, loader_plugins); hnode2 = hash_scan_next(&hscan); assert(hnode2 != NULL); status = cp_uninstall_plugin(ctx, hnode_getkey(hnode2)); assert(status == CP_OK); } hash_delete_free(ctx->env->loaders_to_plugins, hnode); assert(hash_isempty(loader_plugins)); hash_destroy(loader_plugins); cpi_debugf(ctx, N_("The plug-in loader %p was unregistered."), (void *) loader); } cpi_unlock_context(ctx); }
CP_C_API void cp_unregister_ploaders(cp_context_t *ctx) { int found; CHECK_NOT_NULL(ctx); cpi_lock_context(ctx); cpi_check_invocation(ctx, CPI_CF_ANY, __func__); do { hscan_t hscan; hnode_t *hnode; hash_scan_begin(&hscan, ctx->env->loaders_to_plugins); do { hnode = hash_scan_next(&hscan); } while (hnode != NULL && hnode_getkey(hnode) == ctx->env->local_loader); if (hnode != NULL) { cp_plugin_loader_t *loader = (cp_plugin_loader_t *) hnode_getkey(hnode); cp_unregister_ploader(ctx, loader); found = 1; } else { found = 0; } } while (found); cpi_unlock_context(ctx); }
CP_C_API cp_status_t cp_register_pcollection(cp_context_t *context, const char *dir) { cp_status_t status = CP_OK; CHECK_NOT_NULL(context); CHECK_NOT_NULL(dir); cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_ANY, __func__); do { // Initialize plug-in loader if ((status = init_local_ploader(context)) != CP_OK) { break; } // Register directory status = cp_lpl_register_dir(context->env->local_loader, dir); } while (0); // Report error or success if (status != CP_OK) { cpi_errorf(context, N_("The plug-in collection in path %s could not be registered due to insufficient memory."), dir); } else { cpi_debugf(context, N_("The plug-in collection in path %s was registered."), dir); } cpi_unlock_context(context); return status; }
CP_C_API cp_status_t cp_register_logger(cp_context_t *context, cp_logger_func_t logger, void *user_data, cp_log_severity_t min_severity) { logger_t l; logger_t *lh = NULL; lnode_t *node = NULL; cp_status_t status = CP_OK; CHECK_NOT_NULL(context); CHECK_NOT_NULL(logger); cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_LOGGER, __func__); do { // Check if logger already exists and allocate new holder if necessary l.logger = logger; if ((node = list_find(context->env->loggers, &l, comp_logger)) == NULL) { lh = malloc(sizeof(logger_t)); node = lnode_create(lh); if (lh == NULL || node == NULL) { status = CP_ERR_RESOURCE; break; } lh->logger = logger; lh->plugin = context->plugin; list_append(context->env->loggers, node); } else { lh = lnode_get(node); } // Initialize or update the logger holder lh->user_data = user_data; lh->min_severity = min_severity; // Update global limits update_logging_limits(context); } while (0); // Report error if (status == CP_ERR_RESOURCE) { cpi_error(context, N_("Logger could not be registered due to insufficient memory.")); } else if (cpi_is_logged(context, CP_LOG_DEBUG)) { char owner[64]; /* TRANSLATORS: %s is the context owner */ cpi_debugf(context, N_("%s registered a logger."), cpi_context_owner(context, owner, sizeof(owner))); } cpi_unlock_context(context); // Release resources on error if (status != CP_OK) { if (node != NULL) { lnode_destroy(node); } if (lh != NULL) { free(lh); } } return status; }
CP_C_API cp_status_t cp_define_symbol(cp_context_t *context, const char *name, void *ptr) { cp_status_t status = CP_OK; CHECK_NOT_NULL(context); CHECK_NOT_NULL(name); CHECK_NOT_NULL(ptr); if (context->plugin == NULL) { cpi_fatalf(_("Only plug-ins can define context specific symbols.")); } cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_LOGGER | CPI_CF_LISTENER, __func__); do { char *n; // Create a symbol hash if necessary if (context->plugin->defined_symbols == NULL) { if ((context->plugin->defined_symbols = hash_create(HASHCOUNT_T_MAX, (int (*)(const void *, const void *)) strcmp, NULL)) == NULL) { status = CP_ERR_RESOURCE; break; } } // Check for a previously defined symbol if (hash_lookup(context->plugin->defined_symbols, name) != NULL) { status = CP_ERR_CONFLICT; break; } // Insert the symbol into the symbol hash n = strdup(name); if (n == NULL || !hash_alloc_insert(context->plugin->defined_symbols, n, ptr)) { free(n); status = CP_ERR_RESOURCE; break; } } while (0); // Report error if (status != CP_OK) { switch (status) { case CP_ERR_RESOURCE: cpi_errorf(context, N_("Plug-in %s could not define symbol %s due to insufficient memory."), context->plugin->plugin->identifier, name); break; case CP_ERR_CONFLICT: cpi_errorf(context, N_("Plug-in %s tried to redefine symbol %s."), context->plugin->plugin->identifier, name); break; default: break; } } cpi_unlock_context(context); return status; }
CP_C_API int cp_is_logged(cp_context_t *context, cp_log_severity_t severity) { int is_logged; CHECK_NOT_NULL(context); cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_LOGGER, __func__); is_logged = cpi_is_logged(context, severity); cpi_unlock_context(context); return is_logged; }
CP_C_API void cp_unregister_pcollections(cp_context_t *context) { CHECK_NOT_NULL(context); cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_ANY, __func__); if (context->env->local_loader != NULL) { cp_lpl_unregister_dirs(context->env->local_loader); } cpi_debug(context, N_("All plug-in collections were unregistered.")); cpi_unlock_context(context); }
CP_C_API void cp_unregister_pcollection(cp_context_t *context, const char *dir) { CHECK_NOT_NULL(context); CHECK_NOT_NULL(dir); cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_ANY, __func__); if (context->env->local_loader != NULL) { cp_lpl_unregister_dir(context->env->local_loader, dir); } cpi_debugf(context, N_("The plug-in collection in path %s was unregistered."), dir); cpi_unlock_context(context); }
CP_C_API void cp_release_symbol(cp_context_t *context, const void *ptr) { hnode_t *node; symbol_info_t *symbol_info; symbol_provider_info_t *provider_info; CHECK_NOT_NULL(context); CHECK_NOT_NULL(ptr); cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_LOGGER | CPI_CF_LISTENER, __func__); do { // Look up the symbol if ((node = hash_lookup(context->resolved_symbols, ptr)) == NULL) { cpi_errorf(context, N_("Could not release unknown symbol at address %p."), ptr); break; } symbol_info = hnode_get(node); provider_info = symbol_info->provider_info; // Decrease usage count assert(symbol_info->usage_count > 0); symbol_info->usage_count--; assert(provider_info->usage_count > 0); provider_info->usage_count--; // Check if the symbol is not being used anymore if (symbol_info->usage_count == 0) { hash_delete_free(context->resolved_symbols, node); free(symbol_info); if (cpi_is_logged(context, CP_LOG_DEBUG)) { char owner[64]; /* TRANSLATORS: First %s is the context owner */ cpi_debugf(context, _("%s released the symbol at address %p defined by plug-in %s."), cpi_context_owner(context, owner, sizeof(owner)), ptr, provider_info->plugin->plugin->identifier); } } // Check if the symbol providing plug-in is not being used anymore if (provider_info->usage_count == 0) { node = hash_lookup(context->symbol_providers, provider_info->plugin); assert(node != NULL); hash_delete_free(context->symbol_providers, node); if (!provider_info->imported) { cpi_ptrset_remove(context->plugin->imported, provider_info->plugin); cpi_ptrset_remove(provider_info->plugin->importing, context->plugin); cpi_debugf(context, _("A dynamic dependency from plug-in %s to plug-in %s was removed."), context->plugin->plugin->identifier, provider_info->plugin->plugin->identifier); } free(provider_info); } } while (0); cpi_unlock_context(context); }
CP_C_API void cp_log(cp_context_t *context, cp_log_severity_t severity, const char *msg) { CHECK_NOT_NULL(context); CHECK_NOT_NULL(msg); cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_LOGGER, __func__); if (severity < CP_LOG_DEBUG || severity > CP_LOG_ERROR) { cpi_fatalf(_("Illegal severity value in call to %s."), __func__); } if (cpi_is_logged(context, severity)) { do_log(context, severity, msg); } cpi_unlock_context(context); }
CP_C_API void cp_set_context_args(cp_context_t *ctx, char **argv) { int argc; CHECK_NOT_NULL(ctx); CHECK_NOT_NULL(argv); for (argc = 0; argv[argc] != NULL; argc++); if (argc < 1) { cpi_fatalf(_("At least one startup argument must be given in call to function %s."), __func__); } cpi_lock_context(ctx); ctx->env->argc = argc; ctx->env->argv = argv; cpi_unlock_context(ctx); }
CP_C_API void cp_destroy_context(cp_context_t *context) { CHECK_NOT_NULL(context); if (context->plugin != NULL) { cpi_fatalf(_("Only the main program can destroy a plug-in context.")); } // Check invocation cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_ANY, __func__); cpi_unlock_context(context); #ifdef CP_THREADS assert(context->env->mutex == NULL || !cpi_is_mutex_locked(context->env->mutex)); #else assert(!context->env->locked); #endif // Remove context from the context list cpi_lock_framework(); if (contexts != NULL) { lnode_t *node; if ((node = list_find(contexts, context, cpi_comp_ptr)) != NULL) { list_delete(contexts, node); lnode_destroy(node); } } cpi_unlock_framework(); // Unload all plug-ins cp_uninstall_plugins(context); // Unregister all plug-in loaders cp_unregister_ploaders(context); // Unregister implicit local plug-in loader, if any if (context->env->local_loader != NULL) { cp_unregister_ploader(context, context->env->local_loader); } // Release remaining information objects cpi_release_infos(context); // Free context cpi_free_context(context); }
CP_C_API cp_status_t cp_register_ploader(cp_context_t *ctx, cp_plugin_loader_t *loader) { cp_status_t status = CP_OK; hash_t *loader_plugins = NULL; CHECK_NOT_NULL(ctx); CHECK_NOT_NULL(loader); cpi_lock_context(ctx); cpi_check_invocation(ctx, CPI_CF_ANY, __func__); do { if ((loader_plugins = hash_create(HASHCOUNT_T_MAX, (int (*)(const void *, const void *)) strcmp, NULL)) == NULL) { status = CP_ERR_RESOURCE; break; } if (!hash_alloc_insert(ctx->env->loaders_to_plugins, loader, loader_plugins)) { status = CP_ERR_RESOURCE; break; } } while (0); // Report error or success if (status != CP_OK) { cpi_errorf(ctx, N_("The plug-in loader %p could not be registered due to insufficient memory."), (void *) loader); } else { cpi_debugf(ctx, N_("The plug-in loader %p was registered."), (void *) loader); } cpi_unlock_context(ctx); // Release resources if (status != CP_OK) { if (loader_plugins != NULL) { assert(hash_isempty(loader_plugins)); hash_destroy(loader_plugins); } } return status; }
CP_C_API void cp_unregister_logger(cp_context_t *context, cp_logger_func_t logger) { logger_t l; lnode_t *node; CHECK_NOT_NULL(context); CHECK_NOT_NULL(logger); cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_LOGGER, __func__); l.logger = logger; if ((node = list_find(context->env->loggers, &l, comp_logger)) != NULL) { logger_t *lh = lnode_get(node); list_delete(context->env->loggers, node); lnode_destroy(node); free(lh); update_logging_limits(context); } if (cpi_is_logged(context, CP_LOG_DEBUG)) { char owner[64]; /* TRANSLATORS: %s is the context owner */ cpi_debugf(context, N_("%s unregistered a logger."), cpi_context_owner(context, owner, sizeof(owner))); } cpi_unlock_context(context); }
CP_C_API cp_plugin_info_t * cp_load_plugin_descriptor(cp_context_t *context, const char *path, cp_status_t *error) { char *file = NULL; cp_status_t status = CP_OK; FILE *fh = NULL; XML_Parser parser = NULL; ploader_context_t *plcontext = NULL; cp_plugin_info_t *plugin = NULL; CHECK_NOT_NULL(context); CHECK_NOT_NULL(path); cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_ANY, __func__); do { int path_len; // Construct the file name for the plug-in descriptor path_len = strlen(path); if (path_len == 0) { status = CP_ERR_IO; break; } if (path[path_len - 1] == CP_FNAMESEP_CHAR) { path_len--; } file = malloc((path_len + strlen(CP_PLUGIN_DESCRIPTOR) + 2) * sizeof(char)); if (file == NULL) { status = CP_ERR_RESOURCE; break; } strcpy(file, path); file[path_len] = CP_FNAMESEP_CHAR; strcpy(file + path_len + 1, CP_PLUGIN_DESCRIPTOR); // Open the file if ((fh = fopen(file, "rb")) == NULL) { status = CP_ERR_IO; break; } // Initialize the XML parsing parser = XML_ParserCreate(NULL); if (parser == NULL) { status = CP_ERR_RESOURCE; break; } XML_SetElementHandler(parser, start_element_handler, end_element_handler); // Initialize the parsing context if ((plcontext = malloc(sizeof(ploader_context_t))) == NULL) { status = CP_ERR_RESOURCE; break; } memset(plcontext, 0, sizeof(ploader_context_t)); if ((plcontext->plugin = malloc(sizeof(cp_plugin_info_t))) == NULL) { status = CP_ERR_RESOURCE; break; } plcontext->context = context; plcontext->configuration = NULL; plcontext->value = NULL; plcontext->parser = parser; plcontext->file = file; plcontext->state = PARSER_BEGIN; memset(plcontext->plugin, 0, sizeof(cp_plugin_info_t)); plcontext->plugin->name = NULL; plcontext->plugin->identifier = NULL; plcontext->plugin->version = NULL; plcontext->plugin->provider_name = NULL; plcontext->plugin->abi_bw_compatibility = NULL; plcontext->plugin->api_bw_compatibility = NULL; plcontext->plugin->plugin_path = NULL; plcontext->plugin->req_cpluff_version = NULL; plcontext->plugin->imports = NULL; plcontext->plugin->runtime_lib_name = NULL; plcontext->plugin->runtime_funcs_symbol = NULL; plcontext->plugin->ext_points = NULL; plcontext->plugin->extensions = NULL; plcontext->plugin->url = NULL; plcontext->plugin->resourcetype = NULL; XML_SetUserData(parser, plcontext); // Parse the plug-in descriptor while (1) { int bytes_read; void *xml_buffer; int i; // Get buffer from Expat if ((xml_buffer = XML_GetBuffer(parser, CP_XML_PARSER_BUFFER_SIZE)) == NULL) { status = CP_ERR_RESOURCE; break; } // Read data into buffer bytes_read = fread(xml_buffer, 1, CP_XML_PARSER_BUFFER_SIZE, fh); if (ferror(fh)) { status = CP_ERR_IO; break; } // Parse the data if (!(i = XML_ParseBuffer(parser, bytes_read, bytes_read == 0)) && context != NULL) { cpi_lock_context(context); cpi_errorf(context, N_("XML parsing error in %s, line %d, column %d (%s)."), file, XML_GetErrorLineNumber(parser), XML_GetErrorColumnNumber(parser) + 1, XML_ErrorString(XML_GetErrorCode(parser))); cpi_unlock_context(context); } if (!i || plcontext->state == PARSER_ERROR) { status = CP_ERR_MALFORMED; break; } if (bytes_read == 0) { break; } } if (status == CP_OK) { if (plcontext->state != PARSER_END || plcontext->error_count > 0) { status = CP_ERR_MALFORMED; } if (plcontext->resource_error_count > 0) { status = CP_ERR_RESOURCE; } } if (status != CP_OK) { break; } // Initialize the plug-in path *(file + path_len) = '\0'; plcontext->plugin->plugin_path = file; file = NULL; // Increase plug-in usage count if ((status = cpi_register_info(context, plcontext->plugin, (void (*)(cp_context_t *, void *)) dealloc_plugin_info)) != CP_OK) { break; } } while (0); // Report possible errors if (status != CP_OK) { switch (status) { case CP_ERR_MALFORMED: cpi_errorf(context, N_("Plug-in descriptor in %s is invalid."), path); break; case CP_ERR_IO: cpi_errorf(context, N_("An I/O error occurred while loading a plug-in descriptor from %s."), path); break; case CP_ERR_RESOURCE: cpi_errorf(context, N_("Insufficient system resources to load a plug-in descriptor from %s."), path); break; default: cpi_errorf(context, N_("Failed to load a plug-in descriptor from %s."), path); break; } } cpi_unlock_context(context); // Release persistently allocated data on failure if (status != CP_OK) { if (file != NULL) { free(file); file = NULL; } if (plcontext != NULL && plcontext->plugin != NULL) { cpi_free_plugin(plcontext->plugin); plcontext->plugin = NULL; } } // Otherwise copy the plug-in pointer else { plugin = plcontext->plugin; } // Release data allocated for parsing if (parser != NULL) { XML_ParserFree(parser); } if (fh != NULL) { fclose(fh); } if (plcontext != NULL) { if (plcontext->value != NULL) { free(plcontext->value); } free(plcontext); plcontext = NULL; } // Return error code if (error != NULL) { *error = status; } return plugin; }
CP_C_API void * cp_resolve_symbol(cp_context_t *context, const char *id, const char *name, cp_status_t *error) { cp_status_t status = CP_OK; int error_reported = 1; hnode_t *node; void *symbol = NULL; symbol_info_t *symbol_info = NULL; symbol_provider_info_t *provider_info = NULL; cp_plugin_t *pp = NULL; CHECK_NOT_NULL(context); CHECK_NOT_NULL(id); CHECK_NOT_NULL(name); // Resolve the symbol cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_LOGGER | CPI_CF_LISTENER | CPI_CF_STOP, __func__); do { // Allocate space for symbol hashes, if necessary if (context->resolved_symbols == NULL) { context->resolved_symbols = hash_create(HASHCOUNT_T_MAX, cpi_comp_ptr, cpi_hashfunc_ptr); } if (context->symbol_providers == NULL) { context->symbol_providers = hash_create(HASHCOUNT_T_MAX, cpi_comp_ptr, cpi_hashfunc_ptr); } if (context->resolved_symbols == NULL || context->symbol_providers == NULL) { status = CP_ERR_RESOURCE; break; } // Look up the symbol defining plug-in node = hash_lookup(context->env->plugins, id); if (node == NULL) { cpi_warnf(context, N_("Symbol %s in unknown plug-in %s could not be resolved."), name, id); status = CP_ERR_UNKNOWN; break; } pp = hnode_get(node); // Make sure the plug-in has been started if ((status = cpi_start_plugin(context, pp)) != CP_OK) { printf("Symbol %s in plug-in %s could not be resolved because the plug-in could not be started.\n", name, id); cpi_errorf(context, N_("Symbol %s in plug-in %s could not be resolved because the plug-in could not be started."), name, id); error_reported = 1; break; } // Check for a context specific symbol if (pp->defined_symbols != NULL && (node = hash_lookup(pp->defined_symbols, name)) != NULL) { symbol = hnode_get(node); } // Fall back to global symbols, if necessary if (symbol == NULL && pp->runtime_lib != NULL) { symbol = DLSYM(pp->runtime_lib, name); } if (symbol == NULL) { const char *error = DLERROR(); if (error == NULL) { error = _("Unspecified error."); } cpi_warnf(context, N_("Symbol %s in plug-in %s could not be resolved: %s"), name, id, error); status = CP_ERR_UNKNOWN; break; } // Lookup or initialize symbol provider information if ((node = hash_lookup(context->symbol_providers, pp)) != NULL) { provider_info = hnode_get(node); } else { if ((provider_info = malloc(sizeof(symbol_provider_info_t))) == NULL) { status = CP_ERR_RESOURCE; break; } memset(provider_info, 0, sizeof(symbol_provider_info_t)); provider_info->plugin = pp; provider_info->imported = (context->plugin == NULL || cpi_ptrset_contains(context->plugin->imported, pp)); if (!hash_alloc_insert(context->symbol_providers, pp, provider_info)) { status = CP_ERR_RESOURCE; break; } } // Lookup or initialize symbol information if ((node = hash_lookup(context->resolved_symbols, symbol)) != NULL) { symbol_info = hnode_get(node); } else { if ((symbol_info = malloc(sizeof(symbol_info_t))) == NULL) { status = CP_ERR_RESOURCE; break; } memset(symbol_info, 0, sizeof(symbol_info_t)); symbol_info->provider_info = provider_info; if (!hash_alloc_insert(context->resolved_symbols, symbol, symbol_info)) { status = CP_ERR_RESOURCE; break; } } // Add dependencies (for plug-in) if (provider_info != NULL && !provider_info->imported && provider_info->usage_count == 0) { if (!cpi_ptrset_add(context->plugin->imported, pp)) { status = CP_ERR_RESOURCE; break; } if (!cpi_ptrset_add(pp->importing, context->plugin)) { cpi_ptrset_remove(context->plugin->imported, pp); status = CP_ERR_RESOURCE; break; } cpi_debugf(context, "A dynamic dependency was created from plug-in %s to plug-in %s.", context->plugin->plugin->identifier, pp->plugin->identifier); } // Increase usage counts symbol_info->usage_count++; provider_info->usage_count++; if (cpi_is_logged(context, CP_LOG_DEBUG)) { char owner[64]; /* TRANSLATORS: First %s is the context owner */ cpi_debugf(context, "%s resolved symbol %s defined by plug-in %s.", cpi_context_owner(context, owner, sizeof(owner)), name, id); } } while (0); // Clean up if (symbol_info != NULL && symbol_info->usage_count == 0) { if ((node = hash_lookup(context->resolved_symbols, symbol)) != NULL) { hash_delete_free(context->resolved_symbols, node); } free(symbol_info); } if (provider_info != NULL && provider_info->usage_count == 0) { if ((node = hash_lookup(context->symbol_providers, pp)) != NULL) { hash_delete_free(context->symbol_providers, node); } free(provider_info); } // Report insufficient memory error if (status == CP_ERR_RESOURCE && !error_reported) { cpi_errorf(context, N_("Symbol %s in plug-in %s could not be resolved due to insufficient memory."), name, id); } cpi_unlock_context(context); // Return error code if (error != NULL) { *error = status; } // Return symbol return symbol; }
CP_C_API cp_status_t cp_scan_plugins(cp_context_t *context, int flags) { hash_t *avail_plugins = NULL; list_t *started_plugins = NULL; cp_plugin_info_t **plugins = NULL; char *pdir_path = NULL; int pdir_path_size = 0; int plugins_stopped = 0; cp_status_t status = CP_OK; CHECK_NOT_NULL(context); cpi_lock_context(context); cpi_check_invocation(context, CPI_CF_ANY, __func__); cpi_debug(context, N_("Plug-in scan is starting.")); do { lnode_t *lnode; hscan_t hscan; hnode_t *hnode; // Create a hash for available plug-ins if ((avail_plugins = hash_create(HASHCOUNT_T_MAX, (int (*)(const void *, const void *)) strcmp, NULL)) == NULL) { status = CP_ERR_RESOURCE; break; } // Scan plug-in directories for available plug-ins lnode = list_first(context->env->plugin_dirs); while (lnode != NULL) { const char *dir_path; DIR *dir; dir_path = lnode_get(lnode); dir = opendir(dir_path); if (dir != NULL) { int dir_path_len; struct dirent *de; dir_path_len = strlen(dir_path); if (dir_path[dir_path_len - 1] == CP_FNAMESEP_CHAR) { dir_path_len--; } errno = 0; while ((de = readdir(dir)) != NULL) { if (de->d_name[0] != '\0' && de->d_name[0] != '.') { int pdir_path_len = dir_path_len + 1 + strlen(de->d_name) + 1; cp_plugin_info_t *plugin; cp_status_t s; hnode_t *hnode; // Allocate memory for plug-in descriptor path if (pdir_path_size <= pdir_path_len) { char *new_pdir_path; if (pdir_path_size == 0) { pdir_path_size = 128; } while (pdir_path_size <= pdir_path_len) { pdir_path_size *= 2; } new_pdir_path = realloc(pdir_path, pdir_path_size * sizeof(char)); if (new_pdir_path == NULL) { cpi_errorf(context, N_("Could not check possible plug-in location %s%c%s due to insufficient system resources."), dir_path, CP_FNAMESEP_CHAR, de->d_name); status = CP_ERR_RESOURCE; // continue loading plug-ins from other directories continue; } pdir_path = new_pdir_path; } // Construct plug-in descriptor path strcpy(pdir_path, dir_path); pdir_path[dir_path_len] = CP_FNAMESEP_CHAR; strcpy(pdir_path + dir_path_len + 1, de->d_name); // Try to load a plug-in plugin = cp_load_plugin_descriptor(context, pdir_path, &s); if (plugin == NULL) { status = s; // continue loading plug-ins from other directories continue; } // Insert plug-in to the list of available plug-ins if ((hnode = hash_lookup(avail_plugins, plugin->identifier)) != NULL) { cp_plugin_info_t *plugin2 = hnode_get(hnode); if (cpi_vercmp(plugin->version, plugin2->version) > 0) { hash_delete_free(avail_plugins, hnode); cp_release_info(context, plugin2); hnode = NULL; } } if (hnode == NULL) { if (!hash_alloc_insert(avail_plugins, plugin->identifier, plugin)) { cpi_errorf(context, N_("Plug-in %s version %s could not be loaded due to insufficient system resources."), plugin->identifier, plugin->version); cp_release_info(context, plugin); status = CP_ERR_RESOURCE; // continue loading plug-ins from other directories continue; } } } errno = 0; } if (errno) { cpi_errorf(context, N_("Could not read plug-in directory %s: %s"), dir_path, strerror(errno)); status = CP_ERR_IO; // continue loading plug-ins from other directories } closedir(dir); } else { cpi_errorf(context, N_("Could not open plug-in directory %s: %s"), dir_path, strerror(errno)); status = CP_ERR_IO; // continue loading plug-ins from other directories } lnode = list_next(context->env->plugin_dirs, lnode); } // Copy the list of started plug-ins, if necessary if ((flags & CP_SP_RESTART_ACTIVE) && (flags & (CP_SP_UPGRADE | CP_SP_STOP_ALL_ON_INSTALL))) { int i; cp_status_t s; if ((plugins = cp_get_plugins_info(context, &s, NULL)) == NULL) { status = s; break; } if ((started_plugins = list_create(LISTCOUNT_T_MAX)) == NULL) { status = CP_ERR_RESOURCE; break; } for (i = 0; plugins[i] != NULL; i++) { cp_plugin_state_t state; state = cp_get_plugin_state(context, plugins[i]->identifier); if (state == CP_PLUGIN_STARTING || state == CP_PLUGIN_ACTIVE) { char *pid; if ((pid = strdup(plugins[i]->identifier)) == NULL) { status = CP_ERR_RESOURCE; break; } if ((lnode = lnode_create(pid)) == NULL) { free(pid); status = CP_ERR_RESOURCE; break; } list_append(started_plugins, lnode); } } cpi_release_info(context, plugins); plugins = NULL; } // Install/upgrade plug-ins hash_scan_begin(&hscan, avail_plugins); while ((hnode = hash_scan_next(&hscan)) != NULL) { cp_plugin_info_t *plugin; cp_plugin_t *ip = NULL; hnode_t *hn2; int s; plugin = hnode_get(hnode); hn2 = hash_lookup(context->env->plugins, plugin->identifier); if (hn2 != NULL) { ip = hnode_get(hn2); } // Unload the installed plug-in if it is to be upgraded if (ip != NULL && (flags & CP_SP_UPGRADE) && ((ip->plugin->version == NULL && plugin->version != NULL) || (ip->plugin->version != NULL && plugin->version != NULL && cpi_vercmp(plugin->version, ip->plugin->version) > 0))) { if ((flags & (CP_SP_STOP_ALL_ON_UPGRADE | CP_SP_STOP_ALL_ON_INSTALL)) && !plugins_stopped) { plugins_stopped = 1; cp_stop_plugins(context); } s = cp_uninstall_plugin(context, plugin->identifier); assert(s == CP_OK); ip = NULL; } // Install the plug-in, if to be installed if (ip == NULL) { if ((flags & CP_SP_STOP_ALL_ON_INSTALL) && !plugins_stopped) { plugins_stopped = 1; cp_stop_plugins(context); } if ((s = cp_install_plugin(context, plugin)) != CP_OK) { status = s; break; } } // Remove the plug-in from the hash hash_scan_delfree(avail_plugins, hnode); cp_release_info(context, plugin); } // Restart stopped plug-ins if necessary if (started_plugins != NULL) { lnode = list_first(started_plugins); while (lnode != NULL) { char *pid; int s; pid = lnode_get(lnode); s = cp_start_plugin(context, pid); if (s != CP_OK) { status = s; } lnode = list_next(started_plugins, lnode); } } } while (0); // Report error switch (status) { case CP_OK: cpi_debug(context, N_("Plug-in scan has completed successfully.")); break; case CP_ERR_RESOURCE: cpi_error(context, N_("Could not scan plug-ins due to insufficient system resources.")); break; default: cpi_error(context, N_("Could not scan plug-ins.")); break; } cpi_unlock_context(context); // Release resources if (pdir_path != NULL) { free(pdir_path); } if (avail_plugins != NULL) { hscan_t hscan; hnode_t *hnode; hash_scan_begin(&hscan, avail_plugins); while ((hnode = hash_scan_next(&hscan)) != NULL) { cp_plugin_info_t *p = hnode_get(hnode); hash_scan_delfree(avail_plugins, hnode); cp_release_info(context, p); } hash_destroy(avail_plugins); } if (started_plugins != NULL) { list_process(started_plugins, NULL, cpi_process_free_ptr); list_destroy(started_plugins); } if (plugins != NULL) { cp_release_info(context, plugins); } return status; }