iotivity 0.9.0
[platform/upstream/iotivity.git] / service / protocol-plugin / lib / cpluff / libcpluff / pscan.c
1 /*-------------------------------------------------------------------------
2  * C-Pluff, a plug-in framework for C
3  * Copyright 2007 Johannes Lehtinen
4  * 
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:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Software.
14  *
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  *-----------------------------------------------------------------------*/
23
24 /** @file
25  * Plug-in scanning functionality
26  */
27
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35 #include <dirent.h>
36 #include <errno.h>
37 #include "cpluff.h"
38 #include "defines.h"
39 #include "util.h"
40 #include "internal.h"
41
42
43 /* ------------------------------------------------------------------------
44  * Function definitions
45  * ----------------------------------------------------------------------*/
46
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;
55         
56         CHECK_NOT_NULL(context);
57         
58         cpi_lock_context(context);
59         cpi_check_invocation(context, CPI_CF_ANY, __func__);
60         cpi_debug(context, N_("Plug-in scan is starting."));
61         do {
62                 lnode_t *lnode;
63                 hscan_t hscan;
64                 hnode_t *hnode;
65         
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;
69                         break;
70                 }
71         
72                 // Scan plug-in directories for available plug-ins 
73                 lnode = list_first(context->env->plugin_dirs);
74                 while (lnode != NULL) {
75                         const char *dir_path;
76                         DIR *dir;
77                         
78                         dir_path = lnode_get(lnode);
79                         dir = opendir(dir_path);
80                         if (dir != NULL) {
81                                 int dir_path_len;
82                                 struct dirent *de;
83                                 
84                                 dir_path_len = strlen(dir_path);
85                                 if (dir_path[dir_path_len - 1] == CP_FNAMESEP_CHAR) {
86                                         dir_path_len--;
87                                 }
88                                 errno = 0;
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;
93                                                 cp_status_t s;
94                                                 hnode_t *hnode;
95
96                                                 // Allocate memory for plug-in descriptor path 
97                                                 if (pdir_path_size <= pdir_path_len) {
98                                                         char *new_pdir_path;
99                                                 
100                                                         if (pdir_path_size == 0) {
101                                                                 pdir_path_size = 128;
102                                                         }
103                                                         while (pdir_path_size <= pdir_path_len) {
104                                                                 pdir_path_size *= 2;
105                                                         }
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 
111                                                                 continue;
112                                                         }
113                                                         pdir_path = new_pdir_path;
114                                                 }
115                                         
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);
120                                                         
121                                                 // Try to load a plug-in 
122                                                 plugin = cp_load_plugin_descriptor(context, pdir_path, &s);
123                                                 if (plugin == NULL) {
124                                                         status = s;
125                                                         // continue loading plug-ins from other directories 
126                                                         continue;
127                                                 }
128                                         
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);
135                                                                 hnode = NULL;
136                                                         }
137                                                 }
138                                                 if (hnode == NULL) {
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 
144                                                                 continue;
145                                                         }
146                                                 }
147                                                 
148                                         }
149                                         errno = 0;
150                                 }
151                                 if (errno) {
152                                         cpi_errorf(context, N_("Could not read plug-in directory %s: %s"), dir_path, strerror(errno));
153                                         status = CP_ERR_IO;
154                                         // continue loading plug-ins from other directories 
155                                 }
156                                 closedir(dir);
157                         } else {
158                                 cpi_errorf(context, N_("Could not open plug-in directory %s: %s"), dir_path, strerror(errno));
159                                 status = CP_ERR_IO;
160                                 // continue loading plug-ins from other directories 
161                         }
162                         
163                         lnode = list_next(context->env->plugin_dirs, lnode);
164                 }
165                 
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))) {
169                         int i;
170                         cp_status_t s;
171
172                         if ((plugins = cp_get_plugins_info(context, &s, NULL)) == NULL) {
173                                 status = s;
174                                 break;
175                         }
176                         if ((started_plugins = list_create(LISTCOUNT_T_MAX)) == NULL) {
177                                 status = CP_ERR_RESOURCE;
178                                 break;
179                         }
180                         for (i = 0; plugins[i] != NULL; i++) {
181                                 cp_plugin_state_t state;
182                                 
183                                 state = cp_get_plugin_state(context, plugins[i]->identifier);
184                                 if (state == CP_PLUGIN_STARTING || state == CP_PLUGIN_ACTIVE) {
185                                         char *pid;
186                                 
187                                         if ((pid = strdup(plugins[i]->identifier)) == NULL) {
188                                                 status = CP_ERR_RESOURCE;
189                                                 break;
190                                         }
191                                         if ((lnode = lnode_create(pid)) == NULL) {
192                                                 free(pid);
193                                                 status = CP_ERR_RESOURCE;
194                                                 break;
195                                         }
196                                         list_append(started_plugins, lnode);
197                                 }
198                         }
199                         cpi_release_info(context, plugins);
200                         plugins = NULL;
201                 }
202                 
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;
208                         hnode_t *hn2;
209                         int s;
210                         
211                         plugin = hnode_get(hnode);
212                         hn2 = hash_lookup(context->env->plugins, plugin->identifier);
213                         if (hn2 != NULL) {
214                                 ip = hnode_get(hn2);
215                         }
216                         
217                         // Unload the installed plug-in if it is to be upgraded 
218                         if (ip != NULL
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) {
226                                         plugins_stopped = 1;
227                                         cp_stop_plugins(context);
228                                 }
229                                 s = cp_uninstall_plugin(context, plugin->identifier);
230                                 assert(s == CP_OK);
231                                 ip = NULL;
232                         }
233                         
234                         // Install the plug-in, if to be installed 
235                         if (ip == NULL) {
236                                 if ((flags & CP_SP_STOP_ALL_ON_INSTALL) && !plugins_stopped) {
237                                         plugins_stopped = 1;
238                                         cp_stop_plugins(context);
239                                 }
240                                 if ((s = cp_install_plugin(context, plugin)) != CP_OK) {
241                                         status = s;
242                                         break;
243                                 }
244                         }
245                         
246                         // Remove the plug-in from the hash
247                         hash_scan_delfree(avail_plugins, hnode);
248                         cp_release_info(context, plugin);
249                 }
250                 
251                 // Restart stopped plug-ins if necessary 
252                 if (started_plugins != NULL) {
253                         lnode = list_first(started_plugins);
254                         while (lnode != NULL) {
255                                 char *pid;
256                                 int s;
257                                 
258                                 pid = lnode_get(lnode);
259                                 s = cp_start_plugin(context, pid);
260                                 if (s != CP_OK) {
261                                         status = s;
262                                 }
263                                 lnode = list_next(started_plugins, lnode);
264                         }
265                 }
266                 
267         } while (0);
268
269         // Report error
270         switch (status) {
271                 case CP_OK:
272                         cpi_debug(context, N_("Plug-in scan has completed successfully."));
273                         break;
274                 case CP_ERR_RESOURCE:
275                         cpi_error(context, N_("Could not scan plug-ins due to insufficient system resources."));
276                         break;
277                 default:
278                         cpi_error(context, N_("Could not scan plug-ins."));
279                         break;
280         }
281         cpi_unlock_context(context);
282         
283         // Release resources 
284         if (pdir_path != NULL) {
285                 free(pdir_path);
286         }
287         if (avail_plugins != NULL) {
288                 hscan_t hscan;
289                 hnode_t *hnode;
290                 
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);
296                 }
297                 hash_destroy(avail_plugins);
298         }
299         if (started_plugins != NULL) {
300                 list_process(started_plugins, NULL, cpi_process_free_ptr);
301                 list_destroy(started_plugins);
302         }
303         if (plugins != NULL) {
304                 cp_release_info(context, plugins);
305         }
306
307         return status;
308 }