Imported Upstream version 0.9.2
[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 #ifdef __linux__
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/
36 //
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
40 #endif
41 #endif
42
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <assert.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <fcntl.h>
50 #include <dirent.h>
51 #include <errno.h>
52 #include "cpluff.h"
53 #include "defines.h"
54 #include "util.h"
55 #include "internal.h"
56
57
58 /* ------------------------------------------------------------------------
59  * Function definitions
60  * ----------------------------------------------------------------------*/
61
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;
70         
71         CHECK_NOT_NULL(context);
72         
73         cpi_lock_context(context);
74         cpi_check_invocation(context, CPI_CF_ANY, __func__);
75         cpi_debug(context, N_("Plug-in scan is starting."));
76         do {
77                 lnode_t *lnode;
78                 hscan_t hscan;
79                 hnode_t *hnode;
80         
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;
84                         break;
85                 }
86         
87                 // Scan plug-in directories for available plug-ins 
88                 lnode = list_first(context->env->plugin_dirs);
89                 while (lnode != NULL) {
90                         const char *dir_path;
91                         DIR *dir;
92                         
93                         dir_path = lnode_get(lnode);
94                         dir = opendir(dir_path);
95                         if (dir != NULL) {
96                                 int dir_path_len;
97                                 struct dirent *de;
98                                 
99                                 dir_path_len = strlen(dir_path);
100                                 if (dir_path[dir_path_len - 1] == CP_FNAMESEP_CHAR) {
101                                         dir_path_len--;
102                                 }
103                                 errno = 0;
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;
108                                                 cp_status_t s;
109                                                 hnode_t *hnode;
110
111                                                 // Allocate memory for plug-in descriptor path 
112                                                 if (pdir_path_size <= pdir_path_len) {
113                                                         char *new_pdir_path;
114                                                 
115                                                         if (pdir_path_size == 0) {
116                                                                 pdir_path_size = 128;
117                                                         }
118                                                         while (pdir_path_size <= pdir_path_len) {
119                                                                 pdir_path_size *= 2;
120                                                         }
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 
126                                                                 continue;
127                                                         }
128                                                         pdir_path = new_pdir_path;
129                                                 }
130                                         
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);
135                                                         
136                                                 // Try to load a plug-in 
137                                                 plugin = cp_load_plugin_descriptor(context, pdir_path, &s);
138                                                 if (plugin == NULL) {
139                                                         status = s;
140                                                         // continue loading plug-ins from other directories 
141                                                         continue;
142                                                 }
143                                         
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);
150                                                                 hnode = NULL;
151                                                         }
152                                                 }
153                                                 if (hnode == NULL) {
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 
159                                                                 continue;
160                                                         }
161                                                 }
162                                                 
163                                         }
164                                         errno = 0;
165                                 }
166                                 if (errno) {
167                                         cpi_errorf(context, N_("Could not read plug-in directory %s: %s"), dir_path, strerror(errno));
168                                         status = CP_ERR_IO;
169                                         // continue loading plug-ins from other directories 
170                                 }
171                                 closedir(dir);
172                         } else {
173                                 cpi_errorf(context, N_("Could not open plug-in directory %s: %s"), dir_path, strerror(errno));
174                                 status = CP_ERR_IO;
175                                 // continue loading plug-ins from other directories 
176                         }
177                         
178                         lnode = list_next(context->env->plugin_dirs, lnode);
179                 }
180                 
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))) {
184                         int i;
185                         cp_status_t s;
186
187                         if ((plugins = cp_get_plugins_info(context, &s, NULL)) == NULL) {
188                                 status = s;
189                                 break;
190                         }
191                         if ((started_plugins = list_create(LISTCOUNT_T_MAX)) == NULL) {
192                                 status = CP_ERR_RESOURCE;
193                                 break;
194                         }
195                         for (i = 0; plugins[i] != NULL; i++) {
196                                 cp_plugin_state_t state;
197                                 
198                                 state = cp_get_plugin_state(context, plugins[i]->identifier);
199                                 if (state == CP_PLUGIN_STARTING || state == CP_PLUGIN_ACTIVE) {
200                                         char *pid;
201                                 
202                                         if ((pid = strdup(plugins[i]->identifier)) == NULL) {
203                                                 status = CP_ERR_RESOURCE;
204                                                 break;
205                                         }
206                                         if ((lnode = lnode_create(pid)) == NULL) {
207                                                 free(pid);
208                                                 status = CP_ERR_RESOURCE;
209                                                 break;
210                                         }
211                                         list_append(started_plugins, lnode);
212                                 }
213                         }
214                         cpi_release_info(context, plugins);
215                         plugins = NULL;
216                 }
217                 
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;
223                         hnode_t *hn2;
224                         int s;
225                         
226                         plugin = hnode_get(hnode);
227                         hn2 = hash_lookup(context->env->plugins, plugin->identifier);
228                         if (hn2 != NULL) {
229                                 ip = hnode_get(hn2);
230                         }
231                         
232                         // Unload the installed plug-in if it is to be upgraded 
233                         if (ip != NULL
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) {
241                                         plugins_stopped = 1;
242                                         cp_stop_plugins(context);
243                                 }
244                                 s = cp_uninstall_plugin(context, plugin->identifier);
245                                 assert(s == CP_OK);
246                                 ip = NULL;
247                         }
248                         
249                         // Install the plug-in, if to be installed 
250                         if (ip == NULL) {
251                                 if ((flags & CP_SP_STOP_ALL_ON_INSTALL) && !plugins_stopped) {
252                                         plugins_stopped = 1;
253                                         cp_stop_plugins(context);
254                                 }
255                                 if ((s = cp_install_plugin(context, plugin)) != CP_OK) {
256                                         status = s;
257                                         break;
258                                 }
259                         }
260                         
261                         // Remove the plug-in from the hash
262                         hash_scan_delfree(avail_plugins, hnode);
263                         cp_release_info(context, plugin);
264                 }
265                 
266                 // Restart stopped plug-ins if necessary 
267                 if (started_plugins != NULL) {
268                         lnode = list_first(started_plugins);
269                         while (lnode != NULL) {
270                                 char *pid;
271                                 int s;
272                                 
273                                 pid = lnode_get(lnode);
274                                 s = cp_start_plugin(context, pid);
275                                 if (s != CP_OK) {
276                                         status = s;
277                                 }
278                                 lnode = list_next(started_plugins, lnode);
279                         }
280                 }
281                 
282         } while (0);
283
284         // Report error
285         switch (status) {
286                 case CP_OK:
287                         cpi_debug(context, N_("Plug-in scan has completed successfully."));
288                         break;
289                 case CP_ERR_RESOURCE:
290                         cpi_error(context, N_("Could not scan plug-ins due to insufficient system resources."));
291                         break;
292                 default:
293                         cpi_error(context, N_("Could not scan plug-ins."));
294                         break;
295         }
296         cpi_unlock_context(context);
297         
298         // Release resources 
299         if (pdir_path != NULL) {
300                 free(pdir_path);
301         }
302         if (avail_plugins != NULL) {
303                 hscan_t hscan;
304                 hnode_t *hnode;
305                 
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);
311                 }
312                 hash_destroy(avail_plugins);
313         }
314         if (started_plugins != NULL) {
315                 list_process(started_plugins, NULL, cpi_process_free_ptr);
316                 list_destroy(started_plugins);
317         }
318         if (plugins != NULL) {
319                 cp_release_info(context, plugins);
320         }
321
322         return status;
323 }