root/src/noit_module.c

Revision 82dc7d35bbaadf8d6f995fa74cd2135e6764188d, 17.2 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 3 years ago)

These are all memory leak fixes.
They are low priority leaks as they only happen at boot and
only consititue a one-time loss of 200 bytes or so on my box.
Cleanliness is cleanliness.

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  *       notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  *       copyright notice, this list of conditions and the following
13  *       disclaimer in the documentation and/or other materials provided
14  *       with the distribution.
15  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
16  *       of its contributors may be used to endorse or promote products
17  *       derived from this software without specific prior written
18  *       permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "noit_defines.h"
34
35 #include <stdio.h>
36 #include <dlfcn.h>
37
38 #include <libxml/parser.h>
39 #include <libxslt/xslt.h>
40 #include <libxslt/xsltInternals.h>
41 #include <libxslt/transform.h>
42
43 #include "noit_module.h"
44 #include "noit_conf.h"
45 #include "utils/noit_hash.h"
46 #include "utils/noit_log.h"
47
48 static noit_module_t *
49 noit_load_module_image(noit_module_loader_t *loader,
50                        char *module_name,
51                        noit_conf_section_t section);
52
53 noit_module_loader_t __noit_image_loader = {
54   {
55     NOIT_LOADER_MAGIC,
56     NOIT_LOADER_ABI_VERSION,
57     "image",
58     "Basic binary image loader",
59     NULL
60   },
61   NULL,
62   NULL,
63   noit_load_module_image
64 };
65 struct __extended_image_data {
66   void *userdata;
67 };
68
69 static noit_hash_table loaders = NOIT_HASH_EMPTY;
70 static noit_hash_table modules = NOIT_HASH_EMPTY;
71 static noit_hash_table generics = NOIT_HASH_EMPTY;
72 static int noit_module_load_failure_count = 0;
73
74 int noit_module_load_failures() {
75   return noit_module_load_failure_count;
76 }
77 noit_module_loader_t * noit_loader_lookup(const char *name) {
78   void *vloader;
79
80   if(noit_hash_retrieve(&loaders, name, strlen(name), &vloader))
81     return (noit_module_loader_t *)vloader;
82   return NULL;
83 }
84
85 noit_module_t * noit_module_lookup(const char *name) {
86   void *vmodule;
87
88   if(noit_hash_retrieve(&modules, name, strlen(name), &vmodule))
89     return (noit_module_t *)vmodule;
90   return NULL;
91 }
92
93 noit_module_generic_t * noit_module_generic_lookup(const char *name) {
94   void *vmodule;
95
96   if(noit_hash_retrieve(&generics, name, strlen(name), &vmodule))
97     return (noit_module_generic_t *)vmodule;
98   return NULL;
99 }
100
101 static int noit_module_validate_magic(noit_image_t *obj) {
102   if (NOIT_IMAGE_MAGIC(obj) != NOIT_MODULE_MAGIC) return -1;
103   if (NOIT_IMAGE_VERSION(obj) != NOIT_MODULE_ABI_VERSION) return -1;
104   return 0;
105 }
106
107 static int noit_module_generic_validate_magic(noit_image_t *obj) {
108   if (NOIT_IMAGE_MAGIC(obj) != NOIT_GENERIC_MAGIC) return -1;
109   if (NOIT_IMAGE_VERSION(obj) != NOIT_GENERIC_ABI_VERSION) return -1;
110   return 0;
111 }
112
113 static int noit_module_loader_validate_magic(noit_image_t *obj) {
114   if (NOIT_IMAGE_MAGIC(obj) != NOIT_LOADER_MAGIC) return -1;
115   if (NOIT_IMAGE_VERSION(obj) != NOIT_LOADER_ABI_VERSION) return -1;
116   return 0;
117 }
118
119 noit_module_t *noit_blank_module() {
120   noit_module_t *obj;
121   obj = calloc(1, sizeof(*obj));
122   obj->hdr.opaque_handle = calloc(1, sizeof(struct __extended_image_data));
123   return obj;
124 }
125
126 int noit_register_module(noit_module_t *mod) {
127   noit_hash_store(&modules, mod->hdr.name, strlen(mod->hdr.name), mod);
128   return 0;
129 }
130
131 int noit_load_image(const char *file, const char *name,
132                     noit_hash_table *registry,
133                     int (*validate)(noit_image_t *),
134                     size_t obj_size) {
135   char module_file[PATH_MAX];
136   char *base;
137   void *dlhandle;
138   void *dlsymbol;
139   noit_image_t *obj;
140
141   if(!noit_conf_get_string(NULL, "//modules/@directory", &base))
142     base = strdup("");
143
144   if(file[0] == '/')
145     strlcpy(module_file, file, sizeof(module_file));
146   else
147     snprintf(module_file, sizeof(module_file), "%s/%s.%s",
148              base, file, MODULEEXT);
149   free(base);
150
151   dlhandle = dlopen(module_file, RTLD_LAZY | RTLD_GLOBAL);
152   if(!dlhandle) {
153     noitL(noit_stderr, "Cannot open image '%s': %s\n",
154           module_file, dlerror());
155     return -1;
156   }
157
158   dlsymbol = dlsym(dlhandle, name);
159   if(!dlsymbol) {
160     noitL(noit_stderr, "Cannot find '%s' in image '%s': %s\n",
161           name, module_file, dlerror());
162     dlclose(dlhandle);
163     return -1;
164   }
165
166   if(validate(dlsymbol) == -1) {
167     noitL(noit_stderr, "I can't understand image %s\n", name);
168     dlclose(dlhandle);
169     return -1;
170   }
171
172   obj = calloc(1, obj_size);
173   memcpy(obj, dlsymbol, obj_size);
174   obj->opaque_handle = calloc(1, sizeof(struct __extended_image_data));
175
176   if(obj->onload && obj->onload(obj)) {
177     free(obj);
178     return -1;
179   }
180   noit_hash_store(registry, obj->name, strlen(obj->name), obj);
181   return 0;
182 }
183
184 static noit_module_generic_t *
185 noit_load_generic_image(noit_module_loader_t *loader,
186                         char *g_name,
187                         noit_conf_section_t section) {
188   char g_file[PATH_MAX];
189
190   if(!noit_conf_get_stringbuf(section, "ancestor-or-self::node()/@image",
191                               g_file, sizeof(g_file))) {
192     noitL(noit_stderr, "No image defined for %s\n", g_name);
193     return NULL;
194   }
195   if(noit_load_image(g_file, g_name, &generics,
196                      noit_module_generic_validate_magic,
197                      sizeof(noit_module_generic_t))) {
198     noitL(noit_stderr, "Could not load %s:%s\n", g_file, g_name);
199     noit_module_load_failure_count++;
200     return NULL;
201   }
202   return noit_module_generic_lookup(g_name);
203 }
204
205 static noit_module_loader_t *
206 noit_load_loader_image(noit_module_loader_t *loader,
207                        char *loader_name,
208                        noit_conf_section_t section) {
209   char loader_file[PATH_MAX];
210
211   if(!noit_conf_get_stringbuf(section, "ancestor-or-self::node()/@image",
212                               loader_file, sizeof(loader_file))) {
213     noitL(noit_stderr, "No image defined for %s\n", loader_name);
214     return NULL;
215   }
216   if(noit_load_image(loader_file, loader_name, &loaders,
217                      noit_module_loader_validate_magic,
218                      sizeof(noit_module_loader_t))) {
219     noitL(noit_stderr, "Could not load %s:%s\n", loader_file, loader_name);
220     noit_module_load_failure_count++;
221     return NULL;
222   }
223   return noit_loader_lookup(loader_name);
224 }
225
226 static noit_module_t *
227 noit_load_module_image(noit_module_loader_t *loader,
228                        char *module_name,
229                        noit_conf_section_t section) {
230   char module_file[PATH_MAX];
231
232   if(!noit_conf_get_stringbuf(section, "ancestor-or-self::node()/@image",
233                               module_file, sizeof(module_file))) {
234     noitL(noit_stderr, "No image defined for %s\n", module_name);
235     return NULL;
236   }
237   if(noit_load_image(module_file, module_name, &modules,
238                      noit_module_validate_magic, sizeof(noit_module_t))) {
239     noitL(noit_stderr, "Could not load %s:%s\n", module_file, module_name);
240     noit_module_load_failure_count++;
241     return NULL;
242   }
243   return noit_module_lookup(module_name);
244 }
245
246 #include "module-online.h"
247
248 void noit_module_print_help(noit_console_closure_t ncct,
249                             noit_module_t *module, int examples) {
250   const char *params[3] = { NULL };
251   xmlDocPtr help = NULL, output = NULL;
252   xmlOutputBufferPtr out;
253   xmlCharEncodingHandlerPtr enc;
254   static xmlDocPtr helpStyleDoc = NULL;
255   static xsltStylesheetPtr helpStyle = NULL;
256   if(!helpStyle) {
257     if(!helpStyleDoc)
258       helpStyleDoc = xmlParseMemory(helpStyleXML, strlen(helpStyleXML));
259     if(!helpStyleDoc) {
260       nc_printf(ncct, "Invalid XML for style XML\n");
261       return;
262     }
263     helpStyle = xsltParseStylesheetDoc(helpStyleDoc);
264   }
265   if(!helpStyle) {
266     nc_printf(ncct, "no available stylesheet.\n");
267     return;
268   }
269   if(!module) {
270     nc_printf(ncct, "no module\n");
271     return;
272   }
273   if(!module->hdr.xml_description) {
274     nc_printf(ncct, "%s is undocumented, complain to the vendor.\n",
275               module->hdr.name);
276     return;
277   }
278   help = xmlParseMemory(module->hdr.xml_description,
279                         strlen(module->hdr.xml_description));
280   if(!help) {
281     nc_printf(ncct, "%s module has invalid XML documentation.\n",
282               module->hdr.name);
283     return;
284   }
285
286   if(examples) {
287     params[0] = "example";
288     params[1] = "'1'";
289     params[2] = NULL;
290   }
291   output = xsltApplyStylesheet(helpStyle, help, params);
292   if(!output) {
293     nc_printf(ncct, "formatting failed.\n");
294     goto out;
295   }
296
297   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
298   out = xmlOutputBufferCreateIO(noit_console_write_xml,
299                                 noit_console_close_xml,
300                                 ncct, enc);
301   xmlSaveFormatFileTo(out, output, "utf8", 1);
302
303  out:
304   if(help) xmlFreeDoc(help);
305   if(output) xmlFreeDoc(output);
306 }
307
308 char *
309 noit_module_options(noit_console_closure_t ncct,
310                     noit_console_state_stack_t *stack,
311                     noit_console_state_t *state,
312                     int argc, char **argv, int idx) {
313   if(argc == 1) {
314     /* List modules */
315     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
316     const char *name;
317     int klen, i = 0;
318     void *vhdr;
319
320     while(noit_hash_next(&loaders, &iter, (const char **)&name, &klen,
321                          &vhdr)) {
322       noit_image_t *hdr = (noit_image_t *)vhdr;
323       if(!strncmp(hdr->name, argv[0], strlen(argv[0]))) {
324         if(idx == i) return strdup(hdr->name);
325         i++;
326       }
327     }
328     memset(&iter, 0, sizeof(iter));
329     while(noit_hash_next(&modules, &iter, (const char **)&name, &klen,
330                          &vhdr)) {
331       noit_image_t *hdr = (noit_image_t *)vhdr;
332       if(!strncmp(hdr->name, argv[0], strlen(argv[0]))) {
333         if(idx == i) return strdup(hdr->name);
334         i++;
335       }
336     }
337     memset(&iter, 0, sizeof(iter));
338     while(noit_hash_next(&generics, &iter, (const char **)&name, &klen,
339                          &vhdr)) {
340       noit_image_t *hdr = (noit_image_t *)vhdr;
341       if(!strncmp(hdr->name, argv[0], strlen(argv[0]))) {
342         if(idx == i) return strdup(hdr->name);
343         i++;
344       }
345     }
346     return NULL;
347   }
348   if(argc == 2) {
349     if(!strncmp("examples", argv[1], strlen(argv[1])))
350       if(idx == 0) return strdup("examples");
351   }
352   return NULL;
353 }
354 int
355 noit_module_help(noit_console_closure_t ncct,
356                  int argc, char **argv,
357                  noit_console_state_t *state, void *closure) {
358   if(argc == 0) {
359     /* List modules */
360     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
361     const char *name;
362     int klen;
363     void *vhdr;
364
365     nc_printf(ncct, "= Loaders, Modules, and Generics =\n");
366     while(noit_hash_next(&loaders, &iter, (const char **)&name, &klen,
367                          &vhdr)) {
368       noit_image_t *hdr = (noit_image_t *)vhdr;;
369       nc_printf(ncct, "  %s\n", hdr->name);
370     }
371     memset(&iter, 0, sizeof(iter));
372     while(noit_hash_next(&modules, &iter, (const char **)&name, &klen,
373                          &vhdr)) {
374       noit_image_t *hdr = (noit_image_t *)vhdr;;
375       nc_printf(ncct, "  %s\n", hdr->name);
376     }
377     memset(&iter, 0, sizeof(iter));
378     while(noit_hash_next(&generics, &iter, (const char **)&name, &klen,
379                          &vhdr)) {
380       noit_image_t *hdr = (noit_image_t *)vhdr;;
381       nc_printf(ncct, "  %s\n", hdr->name);
382     }
383     return 0;
384   }
385   else if(argc == 1 ||
386           (argc == 2 && !strcmp(argv[1], "examples"))) {
387     /* help for a specific module */
388     noit_module_t *mod;
389     mod = noit_module_lookup(argv[0]);
390     if(!mod) mod = (noit_module_t *)noit_module_generic_lookup(argv[0]);
391     noit_module_print_help(ncct, mod, argc == 2);
392     return 0;
393   }
394   nc_printf(ncct, "help module [ <modulename> [ examples ] ]\n");
395   return -1;
396 }
397
398 void noit_module_init() {
399   noit_conf_section_t *sections;
400   int i, cnt = 0;
401
402   noit_console_add_help("module", noit_module_help, noit_module_options);
403
404   /* Load our generic modules */
405   sections = noit_conf_get_sections(NULL, "//modules//generic", &cnt);
406   for(i=0; i<cnt; i++) {
407     char g_name[256];
408     noit_module_generic_t *gen;
409
410     if(!noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name",
411                                 g_name, sizeof(g_name))) {
412       noitL(noit_stderr, "No name defined in generic stanza %d\n", i+1);
413       continue;
414     }
415     gen = noit_load_generic_image(&__noit_image_loader, g_name,
416                                   sections[i]);
417     if(!gen) {
418       noitL(noit_stderr, "Failed to load generic %s\n", g_name);
419       continue;
420     }
421     if(gen->config) {
422       int rv;
423       noit_hash_table *config;
424       config = noit_conf_get_hash(sections[i], "config");
425       rv = gen->config(gen, config);
426       if(rv == 0) {
427         noit_hash_destroy(config, free, free);
428         free(config);
429       }
430       else if(rv < 0) {
431         noitL(noit_stderr, "Failed to config generic %s\n", g_name);
432         continue;
433       }
434     }
435     if(gen->init && gen->init(gen))
436       noitL(noit_stderr, "Failed to init generic %s\n", g_name);
437     else
438       noitL(noit_stderr, "Generic module %s successfully loaded.\n", g_name);
439   }
440   if(sections) free(sections);
441   /* Load our module loaders */
442   sections = noit_conf_get_sections(NULL, "//modules//loader", &cnt);
443   for(i=0; i<cnt; i++) {
444     char loader_name[256];
445     noit_module_loader_t *loader;
446
447     if(!noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name",
448                                 loader_name, sizeof(loader_name))) {
449       noitL(noit_stderr, "No name defined in loader stanza %d\n", i+1);
450       continue;
451     }
452     loader = noit_load_loader_image(&__noit_image_loader, loader_name,
453                                     sections[i]);
454     if(!loader) {
455       noitL(noit_stderr, "Failed to load loader %s\n", loader_name);
456       continue;
457     }
458     if(loader->config) {
459       int rv;
460       noit_hash_table *config;
461       config = noit_conf_get_hash(sections[i], "config");
462       rv = loader->config(loader, config);
463       if(rv == 0) {
464         noit_hash_destroy(config, free, free);
465         free(config);
466       }
467       else if(rv < 0) {
468         noitL(noit_stderr, "Failed to config loader %s\n", loader_name);
469         continue;
470       }
471     }
472     if(loader->init && loader->init(loader))
473       noitL(noit_stderr, "Failed to init loader %s\n", loader_name);
474   }
475   if(sections) free(sections);
476
477   /* Load the modules (these *are* specific to the /noit/ root) */
478   sections = noit_conf_get_sections(NULL, "/noit/modules//module", &cnt);
479   if(!sections) return;
480   for(i=0; i<cnt; i++) {
481     noit_module_loader_t *loader = &__noit_image_loader;
482     noit_hash_table *config;
483     noit_module_t *module;
484     char loader_name[256];
485     char module_name[256];
486
487     /* If no loader is specified, we should use the image loader */
488     if(!noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name",
489                                 module_name, sizeof(module_name))) {
490       noitL(noit_stderr, "No name defined in module stanza %d\n", i+1);
491       continue;
492     }
493
494     if(noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@loader",
495                                 loader_name, sizeof(loader_name))) {
496       loader = noit_loader_lookup(loader_name);
497       if(!loader) {
498         noitL(noit_stderr, "No '%s' loader found.\n", loader_name);
499         continue;
500       }
501     } else {
502       strlcpy(loader_name, "image", sizeof(loader_name));
503     }
504
505     module = loader->load(loader, module_name, sections[i]);
506     if(!module) {
507       noitL(noit_stderr, "Loader '%s' failed to load '%s'.\n",
508             loader_name, module_name);
509       continue;
510     }
511     if(module->config) {
512       int rv;
513       config = noit_conf_get_hash(sections[i], "config");
514       rv = module->config(module, config);
515       if(rv == 0) {
516         /* Not an error,
517          * but the module didn't take responsibility for the config.
518          */
519         noit_hash_destroy(config, free, free);
520         free(config);
521       }
522       else if(rv < 0) {
523         noitL(noit_stderr,
524               "Configure failed on %s\n", module_name);
525         continue;
526       }
527     }
528     if(module->init && module->init(module)) {
529       noitL(noit_stderr,
530             "Initialized failed on %s\n", module_name);
531       continue;
532     }
533     noitL(noit_stderr, "Module %s successfully loaded.\n", module_name);
534   }
535   free(sections);
536 }
537
538 #define userdata_accessors(type, field) \
539 void *noit_##type##_get_userdata(noit_##type##_t *mod) { \
540   return ((struct __extended_image_data *)mod->field)->userdata; \
541 } \
542 void noit_##type##_set_userdata(noit_##type##_t *mod, void *newdata) { \
543   ((struct __extended_image_data *)mod->field)->userdata = newdata; \
544 }
545
546 userdata_accessors(image, opaque_handle)
547 userdata_accessors(module_loader, hdr.opaque_handle)
548 userdata_accessors(module, hdr.opaque_handle)
Note: See TracBrowser for help on using the browser.