root/src/noit_module.c

Revision 2ff4db5a6730270eb30827e23883ed354c42ddf6, 10.3 kB (checked in by Phil Maddox <philip.maddox@circonus.com>, 5 months ago)

Explicitly Initialize Mtev Hash Tables

Rather than using MTEV_HASH_EMPTY or not calling any initialization at
all, explicitly initialize hash tables.

  • 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;
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       if(!strncmp(name, argv[0], strlen(argv[0]))) {
202         if(idx == i) return strdup(name);
203         i++;
204       }
205     }
206     return NULL;
207   }
208   if(argc == 2) {
209     if(!strncmp("examples", argv[1], strlen(argv[1])))
210       if(idx == 0) return strdup("examples");
211   }
212   return NULL;
213 }
214 int
215 noit_module_help(mtev_console_closure_t ncct,
216                  int argc, char **argv,
217                  mtev_console_state_t *state, void *closure) {
218   if(argc == 0) {
219     /* List modules */
220     mtev_hash_iter iter = MTEV_HASH_ITER_ZERO;
221     const char *name;
222     int klen;
223     void *vhdr;
224
225     nc_printf(ncct, "= Modules =\n");
226     while(mtev_hash_next(&modules, &iter, (const char **)&name, &klen,
227                          &vhdr)) {
228       nc_printf(ncct, "  %s\n", name);
229     }
230     return 0;
231   }
232   else if(argc == 1 ||
233           (argc == 2 && !strcmp(argv[1], "examples"))) {
234     /* help for a specific module */
235     noit_module_t *mod;
236     mod = noit_module_lookup(argv[0]);
237     if(!mod) mod = (noit_module_t *)mtev_dso_generic_lookup(argv[0]);
238     noit_module_print_help(ncct, mod, argc == 2);
239     return 0;
240   }
241   nc_printf(ncct, "help module [ <modulename> [ examples ] ]\n");
242   return -1;
243 }
244
245 void noit_module_init() {
246   mtev_conf_section_t *sections;
247   int i, cnt = 0;
248
249   mtev_dso_add_type("module", noit_module_list_modules);
250   mtev_console_add_help("module", noit_module_help, noit_module_options);
251
252   /* Load the modules (these *are* specific to the /noit/ root) */
253   sections = mtev_conf_get_sections(NULL, "/noit/modules//module", &cnt);
254   if(!sections) cnt = 0;
255   for(i=0; i<cnt; i++) {
256     mtev_dso_loader_t *loader = &__noit_module_loader;
257     mtev_hash_table *config;
258     noit_module_t *module;
259     mtev_conf_section_t *include_sections;
260     char loader_name[256];
261     char module_name[256];
262     int section_cnt;
263
264     /* If no loader is specified, we should use the image loader */
265     if(!mtev_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name",
266                                 module_name, sizeof(module_name))) {
267       mtevL(noit_stderr, "No name defined in module stanza %d\n", i+1);
268       continue;
269     }
270
271     if(mtev_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@loader",
272                                 loader_name, sizeof(loader_name))) {
273       loader = mtev_loader_lookup(loader_name);
274       if(!loader) {
275         mtevL(noit_stderr, "No '%s' loader found.\n", loader_name);
276         noit_module_load_failure_count++;
277         continue;
278       }
279     } else {
280       strlcpy(loader_name, "image", sizeof(loader_name));
281     }
282
283     module = (noit_module_t *)loader->load(loader, module_name, sections[i]);
284     if(!module) {
285       mtevL(noit_stderr, "Loader '%s' failed to load '%s'.\n",
286             loader_name, module_name);
287       noit_module_load_failure_count++;
288       continue;
289     }
290     if(module->config) {
291       int rv;
292       include_sections = mtev_conf_get_sections(sections[i], "include", &section_cnt);
293       if ((include_sections) && (section_cnt == 1)) {
294         config = mtev_conf_get_hash(*include_sections, "config");
295       }
296       else {
297         config = mtev_conf_get_hash(sections[i], "config");
298       }
299       rv = module->config(module, config);
300       if(rv == 0) {
301         /* Not an error,
302          * but the module didn't take responsibility for the config.
303          */
304         mtev_hash_destroy(config, free, free);
305         free(config);
306       }
307       else if(rv < 0) {
308         mtevL(noit_stderr,
309               "Configure failed on %s\n", module_name);
310         continue;
311       }
312       if(include_sections) free(include_sections);
313     }
314     if(module->init && module->init(module)) {
315       mtevL(noit_stderr,
316             "Initialized failed on %s\n", module_name);
317       continue;
318     }
319     mtevL(noit_debug, "Module %s successfully loaded.\n", module_name);
320   }
321   if(cnt) free(sections);
322 }
323
324 void noit_module_init_globals(void) {
325   mtev_hash_init(&modules);
326 }
327
328 #define userdata_accessors(type, field) \
329 void *noit_##type##_get_userdata(noit_##type##_t *mod) { \
330   return mod->field->userdata; \
331 } \
332 void noit_##type##_set_userdata(noit_##type##_t *mod, void *newdata) { \
333   mod->field->userdata = newdata; \
334 }
335
336 userdata_accessors(module, hdr.opaque_handle)
Note: See TracBrowser for help on using the browser.