root/src/noit_module.c

Revision 304ec80b8cf842fc0abe5f9029790908b6455957, 10.3 kB (checked in by Theo Schlossnagle <jesus@omniti.com>, 1 month ago)

Convert to libmtev.

  • Property mode set to 100644
Line 
1 /*
2  * Copyright (c) 2007, OmniTI Computer Consulting, Inc.
3  * All rights reserved.
4  * Copyright (c) 2015, Circonus, Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  *       copyright notice, this list of conditions and the following
14  *       disclaimer in the documentation and/or other materials provided
15  *       with the distribution.
16  *     * Neither the name OmniTI Computer Consulting, Inc. nor the names
17  *       of its contributors may be used to endorse or promote products
18  *       derived from this software without specific prior written
19  *       permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  */
33
34 #include <mtev_defines.h>
35
36 #include <stdio.h>
37 #include <dlfcn.h>
38 #include <assert.h>
39
40 #include <libxml/parser.h>
41 #include <libxslt/xslt.h>
42 #include <libxslt/xsltInternals.h>
43 #include <libxslt/transform.h>
44
45 #include <mtev_conf.h>
46 #include <mtev_hash.h>
47
48 #include "noit_module.h"
49 #include "noit_mtev_bridge.h"
50
51 static mtev_image_t *
52 noit_load_module_image(mtev_dso_loader_t *loader,
53                        char *module_name,
54                        mtev_conf_section_t section);
55
56 mtev_dso_loader_t __noit_module_loader = {
57   {
58     MTEV_LOADER_MAGIC,
59     MTEV_LOADER_ABI_VERSION,
60     "image",
61     "Basic binary image loader",
62     NULL
63   },
64   NULL,
65   NULL,
66   noit_load_module_image
67 };
68
69 static mtev_hash_table modules = MTEV_HASH_EMPTY;
70 static int noit_module_load_failure_count = 0;
71
72 int noit_module_load_failures() {
73   return noit_module_load_failure_count;
74 }
75
76 int
77 noit_module_list_modules(const char ***f) {
78   return mtev_dso_list(&modules, f);
79 }
80
81 noit_module_t * noit_module_lookup(const char *name) {
82   void *vmodule;
83
84   if(mtev_hash_retrieve(&modules, name, strlen(name), &vmodule))
85     return (noit_module_t *)vmodule;
86   return NULL;
87 }
88
89 static int noit_module_validate_magic(mtev_image_t *obj) {
90   if (MTEV_IMAGE_MAGIC(obj) != NOIT_MODULE_MAGIC) return -1;
91   if (MTEV_IMAGE_VERSION(obj) != NOIT_MODULE_ABI_VERSION) return -1;
92   return 0;
93 }
94
95 noit_module_t *noit_blank_module() {
96   noit_module_t *obj;
97   obj = calloc(1, sizeof(*obj));
98   obj->hdr.opaque_handle = mtev_dso_alloc_opaque_handle();
99   return obj;
100 }
101
102 int noit_register_module(noit_module_t *mod) {
103   return !mtev_hash_store(&modules, mod->hdr.name, strlen(mod->hdr.name), mod);
104 }
105
106 static mtev_image_t *
107 noit_load_module_image(mtev_dso_loader_t *loader,
108                        char *module_name,
109                        mtev_conf_section_t section) {
110   char module_file[PATH_MAX];
111
112   if(!mtev_conf_get_stringbuf(section, "ancestor-or-self::node()/@image",
113                               module_file, sizeof(module_file))) {
114     mtevL(noit_stderr, "No image defined for %s\n", module_name);
115     return NULL;
116   }
117   if(mtev_load_image(module_file, module_name, &modules,
118                      noit_module_validate_magic, sizeof(noit_module_t))) {
119     mtevL(noit_stderr, "Could not load module %s:%s\n", module_file, module_name);
120     return NULL;
121   }
122   return (mtev_image_t *)noit_module_lookup(module_name);
123 }
124
125 #include "module-online.h"
126
127 void noit_module_print_help(mtev_console_closure_t ncct,
128                             noit_module_t *module, int examples) {
129   const char *params[3] = { NULL };
130   xmlDocPtr help = NULL, output = NULL;
131   xmlOutputBufferPtr out;
132   xmlCharEncodingHandlerPtr enc;
133   static xmlDocPtr helpStyleDoc = NULL;
134   static xsltStylesheetPtr helpStyle = NULL;
135   if(!helpStyle) {
136     if(!helpStyleDoc)
137       helpStyleDoc = xmlParseMemory(helpStyleXML, strlen(helpStyleXML));
138     if(!helpStyleDoc) {
139       nc_printf(ncct, "Invalid XML for style XML\n");
140       return;
141     }
142     helpStyle = xsltParseStylesheetDoc(helpStyleDoc);
143   }
144   if(!helpStyle) {
145     nc_printf(ncct, "no available stylesheet.\n");
146     return;
147   }
148   if(!module) {
149     nc_printf(ncct, "no module\n");
150     return;
151   }
152   if(!module->hdr.xml_description) {
153     nc_printf(ncct, "%s is undocumented, complain to the vendor.\n",
154               module->hdr.name);
155     return;
156   }
157   help = xmlParseMemory(module->hdr.xml_description,
158                         strlen(module->hdr.xml_description));
159   if(!help) {
160     nc_printf(ncct, "%s module has invalid XML documentation.\n",
161               module->hdr.name);
162     return;
163   }
164
165   if(examples) {
166     params[0] = "example";
167     params[1] = "'1'";
168     params[2] = NULL;
169   }
170   output = xsltApplyStylesheet(helpStyle, help, params);
171   if(!output) {
172     nc_printf(ncct, "formatting failed.\n");
173     goto out;
174   }
175
176   enc = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF8);
177   out = xmlOutputBufferCreateIO(mtev_console_write_xml,
178                                 mtev_console_close_xml,
179                                 ncct, enc);
180   xmlSaveFormatFileTo(out, output, "utf8", 1);
181
182  out:
183   if(help) xmlFreeDoc(help);
184   if(output) xmlFreeDoc(output);
185 }
186
187 char *
188 noit_module_options(mtev_console_closure_t ncct,
189                     mtev_console_state_stack_t *stack,
190                     mtev_console_state_t *state,
191                     int argc, char **argv, int idx) {
192   if(argc == 1) {
193     /* List modules */
194     mtev_hash_iter iter = MTEV_HASH_ITER_ZERO;
195     const char *name;
196     int klen, i = 0;
197     void *vhdr;
198
199     while(mtev_hash_next(&modules, &iter, (const char **)&name, &klen,
200                          &vhdr)) {
201       mtev_image_t *hdr = (mtev_image_t *)vhdr;
202       if(!strncmp(hdr->name, argv[0], strlen(argv[0]))) {
203         if(idx == i) return strdup(hdr->name);
204         i++;
205       }
206     }
207     return NULL;
208   }
209   if(argc == 2) {
210     if(!strncmp("examples", argv[1], strlen(argv[1])))
211       if(idx == 0) return strdup("examples");
212   }
213   return NULL;
214 }
215 int
216 noit_module_help(mtev_console_closure_t ncct,
217                  int argc, char **argv,
218                  mtev_console_state_t *state, void *closure) {
219   if(argc == 0) {
220     /* List modules */
221     mtev_hash_iter iter = MTEV_HASH_ITER_ZERO;
222     const char *name;
223     int klen;
224     void *vhdr;
225
226     nc_printf(ncct, "= Modules =\n");
227     while(mtev_hash_next(&modules, &iter, (const char **)&name, &klen,
228                          &vhdr)) {
229       mtev_image_t *hdr = (mtev_image_t *)vhdr;;
230       nc_printf(ncct, "  %s\n", hdr->name);
231     }
232     return 0;
233   }
234   else if(argc == 1 ||
235           (argc == 2 && !strcmp(argv[1], "examples"))) {
236     /* help for a specific module */
237     noit_module_t *mod;
238     mod = noit_module_lookup(argv[0]);
239     if(!mod) mod = (noit_module_t *)mtev_dso_generic_lookup(argv[0]);
240     noit_module_print_help(ncct, mod, argc == 2);
241     return 0;
242   }
243   nc_printf(ncct, "help module [ <modulename> [ examples ] ]\n");
244   return -1;
245 }
246
247 void noit_module_init() {
248   mtev_conf_section_t *sections;
249   int i, cnt = 0;
250
251   mtev_dso_add_type("module", noit_module_list_modules);
252   mtev_console_add_help("module", noit_module_help, noit_module_options);
253
254   /* Load the modules (these *are* specific to the /noit/ root) */
255   sections = mtev_conf_get_sections(NULL, "/noit/modules//module", &cnt);
256   if(!sections) cnt = 0;
257   for(i=0; i<cnt; i++) {
258     mtev_dso_loader_t *loader = &__noit_module_loader;
259     mtev_hash_table *config;
260     noit_module_t *module;
261     mtev_conf_section_t *include_sections;
262     char loader_name[256];
263     char module_name[256];
264     int section_cnt;
265
266     /* If no loader is specified, we should use the image loader */
267     if(!mtev_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name",
268                                 module_name, sizeof(module_name))) {
269       mtevL(noit_stderr, "No name defined in module stanza %d\n", i+1);
270       continue;
271     }
272
273     if(mtev_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@loader",
274                                 loader_name, sizeof(loader_name))) {
275       loader = mtev_loader_lookup(loader_name);
276       if(!loader) {
277         mtevL(noit_stderr, "No '%s' loader found.\n", loader_name);
278         noit_module_load_failure_count++;
279         continue;
280       }
281     } else {
282       strlcpy(loader_name, "image", sizeof(loader_name));
283     }
284
285     module = (noit_module_t *)loader->load(loader, module_name, sections[i]);
286     if(!module) {
287       mtevL(noit_stderr, "Loader '%s' failed to load '%s'.\n",
288             loader_name, module_name);
289       noit_module_load_failure_count++;
290       continue;
291     }
292     if(module->config) {
293       int rv;
294       include_sections = mtev_conf_get_sections(sections[i], "include", &section_cnt);
295       if ((include_sections) && (section_cnt == 1)) {
296         config = mtev_conf_get_hash(*include_sections, "config");
297       }
298       else {
299         config = mtev_conf_get_hash(sections[i], "config");
300       }
301       rv = module->config(module, config);
302       if(rv == 0) {
303         /* Not an error,
304          * but the module didn't take responsibility for the config.
305          */
306         mtev_hash_destroy(config, free, free);
307         free(config);
308       }
309       else if(rv < 0) {
310         mtevL(noit_stderr,
311               "Configure failed on %s\n", module_name);
312         continue;
313       }
314       if(include_sections) free(include_sections);
315     }
316     if(module->init && module->init(module)) {
317       mtevL(noit_stderr,
318             "Initialized failed on %s\n", module_name);
319       continue;
320     }
321     mtevL(noit_debug, "Module %s successfully loaded.\n", module_name);
322   }
323   if(cnt) free(sections);
324 }
325
326 #define userdata_accessors(type, field) \
327 void *noit_##type##_get_userdata(noit_##type##_t *mod) { \
328   return mod->field->userdata; \
329 } \
330 void noit_##type##_set_userdata(noit_##type##_t *mod, void *newdata) { \
331   mod->field->userdata = newdata; \
332 }
333
334 userdata_accessors(module, hdr.opaque_handle)
Note: See TracBrowser for help on using the browser.