1 /*-------------------------------------------------------------------------
2 * C-Pluff, a plug-in framework for C
3 * Copyright 2007 Johannes Lehtinen
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 *-----------------------------------------------------------------------*/
25 * Plug-in scanning functionality
32 #include <sys/types.h>
43 /* ------------------------------------------------------------------------
44 * Function definitions
45 * ----------------------------------------------------------------------*/
47 CP_C_API cp_status_t cp_scan_plugins(cp_context_t *context, int flags) {
48 hash_t *avail_plugins = NULL;
49 list_t *started_plugins = NULL;
50 cp_plugin_info_t **plugins = NULL;
51 char *pdir_path = NULL;
52 int pdir_path_size = 0;
53 int plugins_stopped = 0;
54 cp_status_t status = CP_OK;
56 CHECK_NOT_NULL(context);
58 cpi_lock_context(context);
59 cpi_check_invocation(context, CPI_CF_ANY, __func__);
60 cpi_debug(context, N_("Plug-in scan is starting."));
66 // Create a hash for available plug-ins
67 if ((avail_plugins = hash_create(HASHCOUNT_T_MAX, (int (*)(const void *, const void *)) strcmp, NULL)) == NULL) {
68 status = CP_ERR_RESOURCE;
72 // Scan plug-in directories for available plug-ins
73 lnode = list_first(context->env->plugin_dirs);
74 while (lnode != NULL) {
78 dir_path = lnode_get(lnode);
79 dir = opendir(dir_path);
84 dir_path_len = strlen(dir_path);
85 if (dir_path[dir_path_len - 1] == CP_FNAMESEP_CHAR) {
89 while ((de = readdir(dir)) != NULL) {
90 if (de->d_name[0] != '\0' && de->d_name[0] != '.') {
91 int pdir_path_len = dir_path_len + 1 + strlen(de->d_name) + 1;
92 cp_plugin_info_t *plugin;
96 // Allocate memory for plug-in descriptor path
97 if (pdir_path_size <= pdir_path_len) {
100 if (pdir_path_size == 0) {
101 pdir_path_size = 128;
103 while (pdir_path_size <= pdir_path_len) {
106 new_pdir_path = realloc(pdir_path, pdir_path_size * sizeof(char));
107 if (new_pdir_path == NULL) {
108 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);
109 status = CP_ERR_RESOURCE;
110 // continue loading plug-ins from other directories
113 pdir_path = new_pdir_path;
116 // Construct plug-in descriptor path
117 strcpy(pdir_path, dir_path);
118 pdir_path[dir_path_len] = CP_FNAMESEP_CHAR;
119 strcpy(pdir_path + dir_path_len + 1, de->d_name);
121 // Try to load a plug-in
122 plugin = cp_load_plugin_descriptor(context, pdir_path, &s);
123 if (plugin == NULL) {
125 // continue loading plug-ins from other directories
129 // Insert plug-in to the list of available plug-ins
130 if ((hnode = hash_lookup(avail_plugins, plugin->identifier)) != NULL) {
131 cp_plugin_info_t *plugin2 = hnode_get(hnode);
132 if (cpi_vercmp(plugin->version, plugin2->version) > 0) {
133 hash_delete_free(avail_plugins, hnode);
134 cp_release_info(context, plugin2);
139 if (!hash_alloc_insert(avail_plugins, plugin->identifier, plugin)) {
140 cpi_errorf(context, N_("Plug-in %s version %s could not be loaded due to insufficient system resources."), plugin->identifier, plugin->version);
141 cp_release_info(context, plugin);
142 status = CP_ERR_RESOURCE;
143 // continue loading plug-ins from other directories
152 cpi_errorf(context, N_("Could not read plug-in directory %s: %s"), dir_path, strerror(errno));
154 // continue loading plug-ins from other directories
158 cpi_errorf(context, N_("Could not open plug-in directory %s: %s"), dir_path, strerror(errno));
160 // continue loading plug-ins from other directories
163 lnode = list_next(context->env->plugin_dirs, lnode);
166 // Copy the list of started plug-ins, if necessary
167 if ((flags & CP_SP_RESTART_ACTIVE)
168 && (flags & (CP_SP_UPGRADE | CP_SP_STOP_ALL_ON_INSTALL))) {
172 if ((plugins = cp_get_plugins_info(context, &s, NULL)) == NULL) {
176 if ((started_plugins = list_create(LISTCOUNT_T_MAX)) == NULL) {
177 status = CP_ERR_RESOURCE;
180 for (i = 0; plugins[i] != NULL; i++) {
181 cp_plugin_state_t state;
183 state = cp_get_plugin_state(context, plugins[i]->identifier);
184 if (state == CP_PLUGIN_STARTING || state == CP_PLUGIN_ACTIVE) {
187 if ((pid = strdup(plugins[i]->identifier)) == NULL) {
188 status = CP_ERR_RESOURCE;
191 if ((lnode = lnode_create(pid)) == NULL) {
193 status = CP_ERR_RESOURCE;
196 list_append(started_plugins, lnode);
199 cpi_release_info(context, plugins);
203 // Install/upgrade plug-ins
204 hash_scan_begin(&hscan, avail_plugins);
205 while ((hnode = hash_scan_next(&hscan)) != NULL) {
206 cp_plugin_info_t *plugin;
207 cp_plugin_t *ip = NULL;
211 plugin = hnode_get(hnode);
212 hn2 = hash_lookup(context->env->plugins, plugin->identifier);
217 // Unload the installed plug-in if it is to be upgraded
219 && (flags & CP_SP_UPGRADE)
220 && ((ip->plugin->version == NULL && plugin->version != NULL)
221 || (ip->plugin->version != NULL
222 && plugin->version != NULL
223 && cpi_vercmp(plugin->version, ip->plugin->version) > 0))) {
224 if ((flags & (CP_SP_STOP_ALL_ON_UPGRADE | CP_SP_STOP_ALL_ON_INSTALL))
225 && !plugins_stopped) {
227 cp_stop_plugins(context);
229 s = cp_uninstall_plugin(context, plugin->identifier);
234 // Install the plug-in, if to be installed
236 if ((flags & CP_SP_STOP_ALL_ON_INSTALL) && !plugins_stopped) {
238 cp_stop_plugins(context);
240 if ((s = cp_install_plugin(context, plugin)) != CP_OK) {
246 // Remove the plug-in from the hash
247 hash_scan_delfree(avail_plugins, hnode);
248 cp_release_info(context, plugin);
251 // Restart stopped plug-ins if necessary
252 if (started_plugins != NULL) {
253 lnode = list_first(started_plugins);
254 while (lnode != NULL) {
258 pid = lnode_get(lnode);
259 s = cp_start_plugin(context, pid);
263 lnode = list_next(started_plugins, lnode);
272 cpi_debug(context, N_("Plug-in scan has completed successfully."));
274 case CP_ERR_RESOURCE:
275 cpi_error(context, N_("Could not scan plug-ins due to insufficient system resources."));
278 cpi_error(context, N_("Could not scan plug-ins."));
281 cpi_unlock_context(context);
284 if (pdir_path != NULL) {
287 if (avail_plugins != NULL) {
291 hash_scan_begin(&hscan, avail_plugins);
292 while ((hnode = hash_scan_next(&hscan)) != NULL) {
293 cp_plugin_info_t *p = hnode_get(hnode);
294 hash_scan_delfree(avail_plugins, hnode);
295 cp_release_info(context, p);
297 hash_destroy(avail_plugins);
299 if (started_plugins != NULL) {
300 list_process(started_plugins, NULL, cpi_process_free_ptr);
301 list_destroy(started_plugins);
303 if (plugins != NULL) {
304 cp_release_info(context, plugins);