Imported Upstream version 0.9.2
[platform/upstream/iotivity.git] / service / protocol-plugin / lib / cpluff / loader / loader.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 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <stdarg.h>
30 #include <string.h>
31 #include <unistd.h>
32 #ifdef HAVE_GETTEXT
33 #include <libintl.h>
34 #include <locale.h>
35 #endif
36 #include <cpluff.h>
37
38
39 /* -----------------------------------------------------------------------
40  * Defines
41  * ---------------------------------------------------------------------*/
42
43 // Gettext defines 
44 #ifdef HAVE_GETTEXT
45 #define _(String) gettext(String)
46 #define gettext_noop(String) String
47 #define N_(String) gettext_noop(String)
48 #else
49 #define _(String) (String)
50 #define N_(String) String
51 #define textdomain(Domain)
52 #define bindtextdomain(Package, Directory)
53 #endif
54
55 // GNU C attribute defines
56 #ifndef CP_GCC_NORETURN
57 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)
58 #define CP_GCC_NORETURN __attribute__((noreturn))
59 #else
60 #define CP_GCC_NORETURN
61 #endif
62 #endif
63
64 // Initializer for empty list
65 #define STR_LIST_INITIALIZER { NULL, NULL }
66
67
68 /* -----------------------------------------------------------------------
69  * Data types
70  * ---------------------------------------------------------------------*/
71
72 /// A type for str_list_t structure
73 typedef struct str_list_t str_list_t;
74
75 /// A type for str_list_entry_t structure
76 typedef struct str_list_entry_t str_list_entry_t;
77
78 /// A string list container
79 struct str_list_t {
80         
81         /// The first entry or NULL if empty
82         str_list_entry_t *first;
83         
84         /// The last entry or NULL if empty
85         str_list_entry_t *last;
86         
87 };
88
89 /// A holder for a string list entry
90 struct str_list_entry_t {
91         
92         /// The string
93         const char *str;
94         
95         /// Next entry
96         str_list_entry_t *next;
97 };
98
99
100 /* -----------------------------------------------------------------------
101  * Variables
102  * ---------------------------------------------------------------------*/
103
104 /// The level of verbosity
105 static int verbosity = 1;
106
107
108 /* -----------------------------------------------------------------------
109  * Functions
110  * ---------------------------------------------------------------------*/
111
112 /**
113  * Prints an error message and exits. In quiet mode the error message is
114  * not printed.
115  * 
116  * @param msg the error message
117  */
118 CP_GCC_NORETURN static void error(const char *msg) {
119         if (verbosity >= 1) {
120                 /* TRANSLATORS: A formatting string for loader error messages. */
121                 fprintf(stderr, _("C-Pluff Loader: ERROR: %s\n"), msg);
122         }
123         exit(1);
124 }
125
126 /**
127  * Formats and prints an error message and exits. In quiet mode the error
128  * message is not printed.
129  * 
130  * @param msg the error message
131  */
132 CP_GCC_NORETURN static void errorf(const char *msg, ...) {
133         char buffer[256];
134         va_list va;
135
136         va_start(va, msg);
137         vsnprintf(buffer, sizeof(buffer), _(msg), va);
138         va_end(va);
139         strcpy(buffer + sizeof(buffer)/sizeof(char) - 4, "...");
140         error(buffer);
141 }
142
143 /**
144  * Allocates memory using malloc and checks for failures.
145  * 
146  * @param size the amount of memory to allocate
147  * @return the allocated memory (always non-NULL)
148  */
149 static void *chk_malloc(size_t size) {
150         void *ptr = malloc(size);
151         if (ptr == NULL) {
152                 error(_("Memory allocation failed."));
153         } else {
154                 return ptr;
155         }
156 }
157
158 /**
159  * Appends a new string to a string list. Copies strings by pointers.
160  */
161 static void str_list_append(str_list_t *list, const char *str) {
162         str_list_entry_t *entry = chk_malloc(sizeof(str_list_entry_t));
163         entry->str = str;
164         entry->next = NULL;
165         if (list->last != NULL) {
166                 list->last->next = entry;
167         }
168         if (list->first == NULL) {
169                 list->first = entry;
170         }
171         list->last = entry;
172 }
173
174 /**
175  * Removes all entries from a string list. Does not free contained strings.
176  */
177 static void str_list_clear(str_list_t *list) {
178         str_list_entry_t *entry = list->first;
179         while (entry != NULL) {
180                 str_list_entry_t *n = entry->next;
181                 free(entry);
182                 entry = n;
183         }
184         list->first = NULL;
185         list->last = NULL;
186 }
187
188 /**
189  * Prints the help text.
190  */
191 static void print_help(void) {
192         printf(_("C-Pluff Loader, version %s\n"), PACKAGE_VERSION);
193         putchar('\n');
194         fputs(_("usage: cpluff-loader <option>... [--] <arguments passed to plug-ins>\n"
195                 "options:\n"
196                 "  -h       print this help text\n"
197                 "  -c DIR   add plug-in collection in directory DIR\n"
198                 "  -p DIR   add plug-in in directory DIR\n"
199                 "  -s PID   start plug-in PID\n"
200                 "  -v       be more verbose (repeat for increased verbosity)\n"
201                 "  -q       be quiet\n"
202                 "  -V       print C-Pluff version number and exit\n"
203                 ), stdout);
204 }
205
206 static void logger(cp_log_severity_t severity, const char *msg, const char *apid, void *dummy) {
207         const char *level;
208         int minv;
209         switch (severity) {
210                 case CP_LOG_DEBUG:
211                         /* TRANSLATORS: A tag for debug level log entries. */
212                         level = _("DEBUG");
213                         minv = 4;
214                         break;
215                 case CP_LOG_INFO:
216                         /* TRANSLATORS: A tag for info level log entries. */
217                         level = _("INFO");
218                         minv = 3;
219                         break;
220                 case CP_LOG_WARNING:
221                         /* TRANSLATORS: A tag for warning level log entries. */
222                         level = _("WARNING");
223                         minv = 2;
224                         break;
225                 case CP_LOG_ERROR:
226                         /* TRANSLATORS: A tag for error level log entries. */
227                         level = _("ERROR");
228                         minv = 1;
229                         break;
230                 default:
231                         /* TRANSLATORS: A tag for unknown severity level. */ 
232                         level = _("UNKNOWN");
233                         minv = 1;
234                         break;
235         }
236         if (verbosity >= minv) {
237                 if (apid != NULL) {
238                         /* TRANSLATORS: A formatting string for log messages caused by plug-in activity. */ 
239                         fprintf(stderr, _("C-Pluff: %s: [%s] %s\n"), level, apid, msg);
240                 } else {
241                         /* TRANSLATORS: A formatting string for log messages caused by loader activity. */ 
242                         fprintf(stderr, _("C-Pluff: %s: [loader] %s\n"), level, msg);
243                 }
244         } 
245 }
246
247 /// The main function
248 int main(int argc, char *argv[]) {
249         int i;
250         str_list_t lst_plugin_collections = STR_LIST_INITIALIZER;
251         str_list_t lst_plugin_dirs = STR_LIST_INITIALIZER;
252         str_list_t lst_start = STR_LIST_INITIALIZER;
253         cp_context_t *context;
254         char **ctx_argv;
255         str_list_entry_t *entry;
256
257         // Set locale
258 #ifdef HAVE_GETTEXT
259         setlocale(LC_ALL, "");
260 #endif
261         
262         // Initialize the framework
263         if (cp_init() != CP_OK) {
264                 error(_("The C-Pluff initialization failed."));
265         }
266         
267         // Set gettext domain 
268 #ifdef HAVE_GETTEXT
269         textdomain(PACKAGE);
270 #endif
271
272         // Parse arguments
273         while ((i = getopt(argc, argv, "hc:p:s:vqV")) != -1) {
274                 switch (i) {
275                         
276                         // Display help and exit
277                         case 'h':
278                                 print_help();
279                                 exit(0);
280
281                         // Add a plug-in collection
282                         case 'c':
283                                 str_list_append(&lst_plugin_collections, optarg);
284                                 break;
285
286                         // Add a single plug-in
287                         case 'p':
288                                 str_list_append(&lst_plugin_dirs, optarg);
289                                 break;
290                                 
291                         // Add a plug-in to be started
292                         case 's':
293                                 str_list_append(&lst_start, optarg);
294                                 break;
295
296                         // Be more verbose
297                         case 'v':
298                                 if (verbosity < 1) {
299                                         error(_("Quiet and verbose modes are mutually exclusive."));
300                                 }
301                                 verbosity++;
302                                 break;
303
304                         // Quiet mode
305                         case 'q':
306                                 if (verbosity > 1) {
307                                         error(_("Quiet and verbose modes are mutually exclusive."));
308                                 }
309                                 verbosity--;
310                                 break;
311
312                         // Display release version and exit
313                         case 'V':
314                                 fputs(cp_get_version(), stdout);
315                                 putchar('\n');
316                                 exit(0);
317                                 
318                         // Unrecognized option
319                         default:
320                                 error(_("Unrecognized option or argument. Try option -h for help."));
321                 }
322         }
323
324         // Display startup information
325         if (verbosity >= 1) {
326                 
327                 /* TRANSLATORS: This is a version string displayed on startup. */
328                 fprintf(stderr, _("C-Pluff Loader, version %s\n"), PACKAGE_VERSION);
329                 
330                 /* TRANSLATORS: This is a version string displayed on startup.
331                    The first %s is version and the second %s is platform type. */
332                 fprintf(stderr, _("C-Pluff Library, version %s for %s\n"),
333                         cp_get_version(), cp_get_host_type());
334         }
335         
336         // Check arguments
337         if (lst_plugin_dirs.first == NULL && lst_plugin_collections.first == NULL) {
338                 error(_("No plug-ins to load. Try option -h for help."));
339         }
340         
341         // Create the context
342         if ((context = cp_create_context(NULL)) == NULL) {
343                 error(_("Plug-in context creation failed."));
344         }
345         
346         // Register logger
347         if (verbosity >= 1) {
348                 cp_log_severity_t mv = CP_LOG_DEBUG;
349                 switch (verbosity) {
350                         case 1:
351                                 mv = CP_LOG_ERROR;
352                                 break;
353                         case 2:
354                                 mv = CP_LOG_WARNING;
355                                 break;
356                         case 3:
357                                 mv = CP_LOG_INFO;
358                                 break;
359                 }
360                 cp_register_logger(context, logger, NULL, mv);
361         }
362         
363         // Set context arguments
364         ctx_argv = chk_malloc((argc - optind + 2) * sizeof(char *));
365         ctx_argv[0] = "";
366         for (i = optind; i < argc; i++) {
367                 ctx_argv[i - optind + 1] = argv[i];
368         }
369         ctx_argv[argc - optind + 1] = NULL;
370         cp_set_context_args(context, ctx_argv);
371
372         // Load individual plug-ins
373         for (entry = lst_plugin_dirs.first; entry != NULL; entry = entry->next) {
374                 cp_plugin_info_t *pi = cp_load_plugin_descriptor(context, entry->str, NULL);
375                 if (pi == NULL) {
376                         errorf(_("Failed to load a plug-in from path %s."), entry->str);
377                 }
378                 if (cp_install_plugin(context, pi) != CP_OK) {
379                         errorf(_("Failed to install plug-in %s."), pi->identifier);
380                 }
381                 cp_release_info(context, pi);
382         }
383         str_list_clear(&lst_plugin_dirs);
384         
385         // Load plug-in collections
386         for (entry = lst_plugin_collections.first; entry != NULL; entry = entry->next) {
387                 if (cp_register_pcollection(context, entry->str) != CP_OK) {
388                         errorf(_("Failed to register a plug-in collection at path %s."), entry->str); 
389                 }
390         }
391         if (lst_plugin_collections.first != NULL
392                 && cp_scan_plugins(context, 0) != CP_OK) {
393                 error(_("Failed to load and install plug-ins from plug-in collections."));
394         }
395         str_list_clear(&lst_plugin_collections);
396         
397         // Start plug-ins
398         for (entry = lst_start.first; entry != NULL; entry = entry->next) {
399                 if (cp_start_plugin(context, entry->str) != CP_OK) {
400                         errorf(_("Failed to start plug-in %s."), entry->str);
401                 }
402         }
403         str_list_clear(&lst_start);
404
405         // Run plug-ins
406         cp_run_plugins(context);
407
408         // Destroy framework
409         cp_destroy();
410         
411         // Release context argument data
412         free(ctx_argv);
413
414         // Return from the main program
415         return 0;
416 }