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
29 #ifndef _POSIX_C_SOURCE
30 // Defining _POSIX_C_SOURCE macro with 200809L (or greater) as value
31 // causes header files to expose definitions
32 // corresponding to the POSIX.1-2008 base
33 // specification (excluding the XSI extension).
34 // For POSIX.1-2008 base specification,
35 // Refer http://pubs.opengroup.org/stage7tc1/
37 // For this specific file, see use of strndup,
38 // Refer http://man7.org/linux/man-pages/man3/strdup.3.html
39 #define _POSIX_C_SOURCE 200809L
47 #include <sys/types.h>
58 /* ------------------------------------------------------------------------
59 * Function definitions
60 * ----------------------------------------------------------------------*/
62 CP_C_API cp_status_t cp_scan_plugins(cp_context_t *context, int flags) {
63 hash_t *avail_plugins = NULL;
64 list_t *started_plugins = NULL;
65 cp_plugin_info_t **plugins = NULL;
66 char *pdir_path = NULL;
67 int pdir_path_size = 0;
68 int plugins_stopped = 0;
69 cp_status_t status = CP_OK;
71 CHECK_NOT_NULL(context);
73 cpi_lock_context(context);
74 cpi_check_invocation(context, CPI_CF_ANY, __func__);
75 cpi_debug(context, N_("Plug-in scan is starting."));
81 // Create a hash for available plug-ins
82 if ((avail_plugins = hash_create(HASHCOUNT_T_MAX, (int (*)(const void *, const void *)) strcmp, NULL)) == NULL) {
83 status = CP_ERR_RESOURCE;
87 // Scan plug-in directories for available plug-ins
88 lnode = list_first(context->env->plugin_dirs);
89 while (lnode != NULL) {
93 dir_path = lnode_get(lnode);
94 dir = opendir(dir_path);
99 dir_path_len = strlen(dir_path);
100 if (dir_path[dir_path_len - 1] == CP_FNAMESEP_CHAR) {
104 while ((de = readdir(dir)) != NULL) {
105 if (de->d_name[0] != '\0' && de->d_name[0] != '.') {
106 int pdir_path_len = dir_path_len + 1 + strlen(de->d_name) + 1;
107 cp_plugin_info_t *plugin;
111 // Allocate memory for plug-in descriptor path
112 if (pdir_path_size <= pdir_path_len) {
115 if (pdir_path_size == 0) {
116 pdir_path_size = 128;
118 while (pdir_path_size <= pdir_path_len) {
121 new_pdir_path = realloc(pdir_path, pdir_path_size * sizeof(char));
122 if (new_pdir_path == NULL) {
123 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);
124 status = CP_ERR_RESOURCE;
125 // continue loading plug-ins from other directories
128 pdir_path = new_pdir_path;
131 // Construct plug-in descriptor path
132 strcpy(pdir_path, dir_path);
133 pdir_path[dir_path_len] = CP_FNAMESEP_CHAR;
134 strcpy(pdir_path + dir_path_len + 1, de->d_name);
136 // Try to load a plug-in
137 plugin = cp_load_plugin_descriptor(context, pdir_path, &s);
138 if (plugin == NULL) {
140 // continue loading plug-ins from other directories
144 // Insert plug-in to the list of available plug-ins
145 if ((hnode = hash_lookup(avail_plugins, plugin->identifier)) != NULL) {
146 cp_plugin_info_t *plugin2 = hnode_get(hnode);
147 if (cpi_vercmp(plugin->version, plugin2->version) > 0) {
148 hash_delete_free(avail_plugins, hnode);
149 cp_release_info(context, plugin2);
154 if (!hash_alloc_insert(avail_plugins, plugin->identifier, plugin)) {
155 cpi_errorf(context, N_("Plug-in %s version %s could not be loaded due to insufficient system resources."), plugin->identifier, plugin->version);
156 cp_release_info(context, plugin);
157 status = CP_ERR_RESOURCE;
158 // continue loading plug-ins from other directories
167 cpi_errorf(context, N_("Could not read plug-in directory %s: %s"), dir_path, strerror(errno));
169 // continue loading plug-ins from other directories
173 cpi_errorf(context, N_("Could not open plug-in directory %s: %s"), dir_path, strerror(errno));
175 // continue loading plug-ins from other directories
178 lnode = list_next(context->env->plugin_dirs, lnode);
181 // Copy the list of started plug-ins, if necessary
182 if ((flags & CP_SP_RESTART_ACTIVE)
183 && (flags & (CP_SP_UPGRADE | CP_SP_STOP_ALL_ON_INSTALL))) {
187 if ((plugins = cp_get_plugins_info(context, &s, NULL)) == NULL) {
191 if ((started_plugins = list_create(LISTCOUNT_T_MAX)) == NULL) {
192 status = CP_ERR_RESOURCE;
195 for (i = 0; plugins[i] != NULL; i++) {
196 cp_plugin_state_t state;
198 state = cp_get_plugin_state(context, plugins[i]->identifier);
199 if (state == CP_PLUGIN_STARTING || state == CP_PLUGIN_ACTIVE) {
202 if ((pid = strdup(plugins[i]->identifier)) == NULL) {
203 status = CP_ERR_RESOURCE;
206 if ((lnode = lnode_create(pid)) == NULL) {
208 status = CP_ERR_RESOURCE;
211 list_append(started_plugins, lnode);
214 cpi_release_info(context, plugins);
218 // Install/upgrade plug-ins
219 hash_scan_begin(&hscan, avail_plugins);
220 while ((hnode = hash_scan_next(&hscan)) != NULL) {
221 cp_plugin_info_t *plugin;
222 cp_plugin_t *ip = NULL;
226 plugin = hnode_get(hnode);
227 hn2 = hash_lookup(context->env->plugins, plugin->identifier);
232 // Unload the installed plug-in if it is to be upgraded
234 && (flags & CP_SP_UPGRADE)
235 && ((ip->plugin->version == NULL && plugin->version != NULL)
236 || (ip->plugin->version != NULL
237 && plugin->version != NULL
238 && cpi_vercmp(plugin->version, ip->plugin->version) > 0))) {
239 if ((flags & (CP_SP_STOP_ALL_ON_UPGRADE | CP_SP_STOP_ALL_ON_INSTALL))
240 && !plugins_stopped) {
242 cp_stop_plugins(context);
244 s = cp_uninstall_plugin(context, plugin->identifier);
249 // Install the plug-in, if to be installed
251 if ((flags & CP_SP_STOP_ALL_ON_INSTALL) && !plugins_stopped) {
253 cp_stop_plugins(context);
255 if ((s = cp_install_plugin(context, plugin)) != CP_OK) {
261 // Remove the plug-in from the hash
262 hash_scan_delfree(avail_plugins, hnode);
263 cp_release_info(context, plugin);
266 // Restart stopped plug-ins if necessary
267 if (started_plugins != NULL) {
268 lnode = list_first(started_plugins);
269 while (lnode != NULL) {
273 pid = lnode_get(lnode);
274 s = cp_start_plugin(context, pid);
278 lnode = list_next(started_plugins, lnode);
287 cpi_debug(context, N_("Plug-in scan has completed successfully."));
289 case CP_ERR_RESOURCE:
290 cpi_error(context, N_("Could not scan plug-ins due to insufficient system resources."));
293 cpi_error(context, N_("Could not scan plug-ins."));
296 cpi_unlock_context(context);
299 if (pdir_path != NULL) {
302 if (avail_plugins != NULL) {
306 hash_scan_begin(&hscan, avail_plugins);
307 while ((hnode = hash_scan_next(&hscan)) != NULL) {
308 cp_plugin_info_t *p = hnode_get(hnode);
309 hash_scan_delfree(avail_plugins, hnode);
310 cp_release_info(context, p);
312 hash_destroy(avail_plugins);
314 if (started_plugins != NULL) {
315 list_process(started_plugins, NULL, cpi_process_free_ptr);
316 list_destroy(started_plugins);
318 if (plugins != NULL) {
319 cp_release_info(context, plugins);