root/src/noit_module.c

Revision db656f3332551668dbf8656d8dcd05fe917ddcd7, 11.2 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 6 years ago)

pull help and docs into the console, refs #21

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