root/src/noit_module.c

Revision 6210da7ee0e2ed143d71a8e00b709f16e71059f8, 12.4 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 5 years ago)

various changes to avoid dereferencing type-punned pointers and breaking strict-aliasing rules, refs #34

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  */
5
6 #include "noit_defines.h"
7
8 #include <stdio.h>
9 #include <dlfcn.h>
10
11 #include <libxml/parser.h>
12 #include <libxslt/xslt.h>
13 #include <libxslt/xsltInternals.h>
14 #include <libxslt/transform.h>
15
16 #include "noit_module.h"
17 #include "noit_conf.h"
18 #include "utils/noit_hash.h"
19 #include "utils/noit_log.h"
20
21 static noit_module_t *
22 noit_load_module_image(noit_module_loader_t *loader,
23                        char *module_name,
24                        noit_conf_section_t section);
25
26 noit_module_loader_t __noit_image_loader = {
27   {
28     NOIT_LOADER_MAGIC,
29     NOIT_LOADER_ABI_VERSION,
30     "image",
31     "Basic binary image loader",
32     NULL
33   },
34   NULL,
35   NULL,
36   noit_load_module_image
37 };
38 struct __extended_image_data {
39   void *userdata;
40 };
41
42 static noit_hash_table loaders = NOIT_HASH_EMPTY;
43 static noit_hash_table modules = NOIT_HASH_EMPTY;
44
45 noit_module_loader_t * noit_loader_lookup(const char *name) {
46   void *vloader;
47
48   if(noit_hash_retrieve(&loaders, name, strlen(name), &vloader))
49     return (noit_module_loader_t *)vloader;
50   return NULL;
51 }
52
53 noit_module_t * noit_module_lookup(const char *name) {
54   void *vmodule;
55
56   if(noit_hash_retrieve(&modules, name, strlen(name), &vmodule))
57     return (noit_module_t *)vmodule;
58   return NULL;
59 }
60
61 static int noit_module_validate_magic(noit_image_t *obj) {
62   if (NOIT_IMAGE_MAGIC(obj) != NOIT_MODULE_MAGIC) return -1;
63   if (NOIT_IMAGE_VERSION(obj) != NOIT_MODULE_ABI_VERSION) return -1;
64   return 0;
65 }
66
67 static int noit_module_loader_validate_magic(noit_image_t *obj) {
68   if (NOIT_IMAGE_MAGIC(obj) != NOIT_LOADER_MAGIC) return -1;
69   if (NOIT_IMAGE_VERSION(obj) != NOIT_LOADER_ABI_VERSION) return -1;
70   return 0;
71 }
72
73 noit_module_t *noit_blank_module() {
74   noit_module_t *obj;
75   obj = calloc(1, sizeof(*obj));
76   obj->hdr.opaque_handle = calloc(1, sizeof(struct __extended_image_data));
77   return obj;
78 }
79
80 int noit_register_module(noit_module_t *mod) {
81   noit_hash_store(&modules, mod->hdr.name, strlen(mod->hdr.name), mod);
82   return 0;
83 }
84
85 int noit_load_image(const char *file, const char *name,
86                     noit_hash_table *registry,
87                     int (*validate)(noit_image_t *),
88                     size_t obj_size) {
89   char module_file[PATH_MAX];
90   char *base;
91   void *dlhandle;
92   void *dlsymbol;
93   noit_image_t *obj;
94
95   if(!noit_conf_get_string(NULL, "/noit/modules/@directory", &base))
96     base = strdup("");
97
98   if(file[0] == '/')
99     strlcpy(module_file, file, sizeof(module_file));
100   else
101     snprintf(module_file, sizeof(module_file), "%s/%s.%s",
102              base, file, MODULEEXT);
103   free(base);
104
105   dlhandle = dlopen(module_file, RTLD_LAZY | RTLD_GLOBAL);
106   if(!dlhandle) {
107     noitL(noit_stderr, "Cannot open image '%s': %s\n",
108           module_file, dlerror());
109     return -1;
110   }
111
112   dlsymbol = dlsym(dlhandle, name);
113   if(!dlsymbol) {
114     noitL(noit_stderr, "Cannot find '%s' in image '%s': %s\n",
115           name, module_file, dlerror());
116     dlclose(dlhandle);
117     return -1;
118   }
119
120   if(validate(dlsymbol) == -1) {
121     noitL(noit_stderr, "I can't understand image %s\n", name);
122     dlclose(dlhandle);
123     return -1;
124   }
125
126   obj = calloc(1, obj_size);
127   memcpy(obj, dlsymbol, obj_size);
128   obj->opaque_handle = calloc(1, sizeof(struct __extended_image_data));
129
130   if(obj->onload && obj->onload(obj)) {
131     free(obj);
132     return -1;
133   }
134   noit_hash_store(registry, obj->name, strlen(obj->name), obj);
135   return 0;
136 }
137
138 static noit_module_loader_t *
139 noit_load_loader_image(noit_module_loader_t *loader,
140                        char *loader_name,
141                        noit_conf_section_t section) {
142   char loader_file[PATH_MAX];
143
144   if(!noit_conf_get_stringbuf(section, "ancestor-or-self::node()/@image",
145                               loader_file, sizeof(loader_file))) {
146     noitL(noit_stderr, "No image defined for %s\n", loader_name);
147     return NULL;
148   }
149   if(noit_load_image(loader_file, loader_name, &loaders,
150                      noit_module_loader_validate_magic,
151                      sizeof(noit_module_loader_t))) {
152     noitL(noit_stderr, "Could not load %s:%s\n", loader_file, loader_name);
153     return NULL;
154   }
155   return noit_loader_lookup(loader_name);
156 }
157
158 static noit_module_t *
159 noit_load_module_image(noit_module_loader_t *loader,
160                        char *module_name,
161                        noit_conf_section_t section) {
162   char module_file[PATH_MAX];
163
164   if(!noit_conf_get_stringbuf(section, "ancestor-or-self::node()/@image",
165                               module_file, sizeof(module_file))) {
166     noitL(noit_stderr, "No image defined for %s\n", module_name);
167     return NULL;
168   }
169   if(noit_load_image(module_file, module_name, &modules,
170                      noit_module_validate_magic, sizeof(noit_module_t))) {
171     noitL(noit_stderr, "Could not load %s:%s\n", module_file, module_name);
172     return NULL;
173   }
174   return noit_module_lookup(module_name);
175 }
176
177 #include "module-online.h"
178
179 void noit_module_print_help(noit_console_closure_t ncct,
180                             noit_module_t *module, int examples) {
181   const char *params[3] = { NULL };
182   xmlDocPtr help = NULL, output = NULL;
183   xmlOutputBufferPtr out;
184   xmlCharEncodingHandlerPtr enc;
185   static xmlDocPtr helpStyleDoc = NULL;
186   static xsltStylesheetPtr helpStyle = NULL;
187   if(!helpStyle) {
188     if(!helpStyleDoc)
189       helpStyleDoc = xmlParseMemory(helpStyleXML, strlen(helpStyleXML));
190     if(!helpStyleDoc) {
191       nc_printf(ncct, "Invalid XML for style XML\n");
192       return;
193     }
194     helpStyle = xsltParseStylesheetDoc(helpStyleDoc);
195   }
196   if(!helpStyle) {
197     nc_printf(ncct, "no available stylesheet.\n");
198     return;
199   }
200   if(!module) {
201     nc_printf(ncct, "no module\n");
202     return;
203   }
204   if(!module->hdr.xml_description) {
205     nc_printf(ncct, "%s is undocumented, complain to the vendor.\n",
206               module->hdr.name);
207     return;
208   }
209   help = xmlParseMemory(module->hdr.xml_description,
210                         strlen(module->hdr.xml_description));
211   if(!help) {
212     nc_printf(ncct, "%s module has invalid XML documentation.\n",
213               module->hdr.name);
214     return;
215   }
216
217   if(examples) {
218     params[0] = "example";
219     params[1] = "'1'";
220     params[2] = NULL;
221   }
222   output = xsltApplyStylesheet(helpStyle, help, params);
223   if(!output) {
224     nc_printf(ncct, "formatting failed.\n");
225     goto out;
226   }
227
228   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
229   out = xmlOutputBufferCreateIO(noit_console_write_xml,
230                                 noit_console_close_xml,
231                                 ncct, enc);
232   xmlSaveFormatFileTo(out, output, "utf8", 1);
233
234  out:
235   if(help) xmlFreeDoc(help);
236   if(output) xmlFreeDoc(output);
237 }
238
239 char *
240 noit_module_options(noit_console_closure_t ncct,
241                     noit_console_state_stack_t *stack,
242                     noit_console_state_t *state,
243                     int argc, char **argv, int idx) {
244   if(argc == 1) {
245     /* List modules */
246     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
247     const char *name;
248     int klen, i = 0;
249     void *vhdr;
250
251     while(noit_hash_next(&loaders, &iter, (const char **)&name, &klen,
252                          &vhdr)) {
253       noit_image_t *hdr = (noit_image_t *)vhdr;
254       if(!strncmp(hdr->name, argv[0], strlen(argv[0]))) {
255         if(idx == i) return strdup(hdr->name);
256         i++;
257       }
258     }
259     memset(&iter, 0, sizeof(iter));
260     while(noit_hash_next(&modules, &iter, (const char **)&name, &klen,
261                          &vhdr)) {
262       noit_image_t *hdr = (noit_image_t *)vhdr;
263       if(!strncmp(hdr->name, argv[0], strlen(argv[0]))) {
264         if(idx == i) return strdup(hdr->name);
265         i++;
266       }
267     }
268     return NULL;
269   }
270   if(argc == 2) {
271     if(!strncmp("examples", argv[1], strlen(argv[1])))
272       if(idx == 0) return strdup("examples");
273   }
274   return NULL;
275 }
276 int
277 noit_module_help(noit_console_closure_t ncct,
278                  int argc, char **argv,
279                  noit_console_state_t *state, void *closure) {
280   if(argc == 0) {
281     /* List modules */
282     noit_hash_iter iter = NOIT_HASH_ITER_ZERO;
283     const char *name;
284     int klen;
285     void *vhdr;
286
287     nc_printf(ncct, "= Loaders and Modules =\n");
288     while(noit_hash_next(&loaders, &iter, (const char **)&name, &klen,
289                          &vhdr)) {
290       noit_image_t *hdr = (noit_image_t *)vhdr;;
291       nc_printf(ncct, "  %s\n", hdr->name);
292     }
293     memset(&iter, 0, sizeof(iter));
294     while(noit_hash_next(&modules, &iter, (const char **)&name, &klen,
295                          &vhdr)) {
296       noit_image_t *hdr = (noit_image_t *)vhdr;;
297       nc_printf(ncct, "  %s\n", hdr->name);
298     }
299     return 0;
300   }
301   else if(argc == 1 ||
302           (argc == 2 && !strcmp(argv[1], "examples"))) {
303     /* help for a specific module */
304     noit_module_t *mod;
305     mod = noit_module_lookup(argv[0]);
306     noit_module_print_help(ncct, mod, argc == 2);
307     return 0;
308   }
309   nc_printf(ncct, "help module [ <modulename> [ examples ] ]\n");
310   return -1;
311 }
312
313 void noit_module_init() {
314   noit_conf_section_t *sections;
315   int i, cnt = 0;
316
317   noit_console_add_help("module", noit_module_help, noit_module_options);
318
319   /* Load our module loaders */
320   sections = noit_conf_get_sections(NULL, "/noit/modules//loader", &cnt);
321   for(i=0; i<cnt; i++) {
322     char loader_name[256];
323     noit_module_loader_t *loader;
324
325     if(!noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name",
326                                 loader_name, sizeof(loader_name))) {
327       noitL(noit_stderr, "No name defined in loader stanza %d\n", i+1);
328       continue;
329     }
330     loader = noit_load_loader_image(&__noit_image_loader, loader_name,
331                                     sections[i]);
332     if(!loader) {
333       noitL(noit_stderr, "Failed to load loader %s\n", loader_name);
334       continue;
335     }
336     if(loader->config) {
337       int rv;
338       noit_hash_table *config;
339       config = noit_conf_get_hash(sections[i], "config");
340       rv = loader->config(loader, config);
341       if(rv == 0) {
342         noit_hash_destroy(config, free, free);
343         free(config);
344       }
345       else if(rv < 0) {
346         noitL(noit_stderr, "Failed to config loader %s\n", loader_name);
347         continue;
348       }
349     }
350     if(loader->init && loader->init(loader))
351       noitL(noit_stderr, "Failed to init loader %s\n", loader_name);
352   }
353   if(sections) free(sections);
354
355   /* Load the modules */
356   sections = noit_conf_get_sections(NULL, "/noit/modules//module", &cnt);
357   if(!sections) return;
358   for(i=0; i<cnt; i++) {
359     noit_module_loader_t *loader = &__noit_image_loader;
360     noit_hash_table *config;
361     noit_module_t *module;
362     char loader_name[256];
363     char module_name[256];
364
365     /* If no loader is specified, we should use the image loader */
366     if(!noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name",
367                                 module_name, sizeof(module_name))) {
368       noitL(noit_stderr, "No name defined in module stanza %d\n", i+1);
369       continue;
370     }
371
372     if(noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@loader",
373                                 loader_name, sizeof(loader_name))) {
374       loader = noit_loader_lookup(loader_name);
375       if(!loader) {
376         noitL(noit_stderr, "No '%s' loader found.\n", loader_name);
377         continue;
378       }
379     } else {
380       strlcpy(loader_name, "image", sizeof(loader_name));
381     }
382
383     module = loader->load(loader, module_name, sections[i]);
384     if(!module) {
385       noitL(noit_stderr, "Loader '%s' failed to load '%s'.\n",
386             loader_name, module_name);
387       continue;
388     }
389     config = noit_conf_get_hash(sections[i], "config");
390     if(module->config) {
391       int rv;
392       rv = module->config(module, config);
393       if(rv == 0) {
394         /* Not an error,
395          * but the module didn't take responsibility for the config.
396          */
397         noit_hash_destroy(config, free, free);
398         free(config);
399       }
400       else if(rv < 0) {
401         noitL(noit_stderr,
402               "Configure failed on %s\n", module_name);
403         continue;
404       }
405     }
406     if(module->init && module->init(module)) {
407       noitL(noit_stderr,
408             "Initialized failed on %s\n", module_name);
409       continue;
410     }
411     noitL(noit_stderr, "Module %s successfully loaded.\n", module_name);
412   }
413   free(sections);
414 }
415
416 #define userdata_accessors(type, field) \
417 void *noit_##type##_get_userdata(noit_##type##_t *mod) { \
418   return ((struct __extended_image_data *)mod->field)->userdata; \
419 } \
420 void noit_##type##_set_userdata(noit_##type##_t *mod, void *newdata) { \
421   ((struct __extended_image_data *)mod->field)->userdata = newdata; \
422 }
423
424 userdata_accessors(image, opaque_handle)
425 userdata_accessors(module_loader, hdr.opaque_handle)
426 userdata_accessors(module, hdr.opaque_handle)
Note: See TracBrowser for help on using the browser.