root/src/noit_module.c

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

make the loading mechanism generic so that we can load something other than checkers. refs #28

  • 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 "noit_module.h"
12 #include "noit_conf.h"
13 #include "utils/noit_hash.h"
14 #include "utils/noit_log.h"
15
16 static noit_module_t *
17 noit_load_module_image(noit_module_loader_t *loader,
18                        char *module_name,
19                        noit_conf_section_t section);
20
21 noit_module_loader_t __noit_image_loader = {
22   {
23     NOIT_LOADER_MAGIC,
24     NOIT_LOADER_ABI_VERSION,
25     "image",
26     "Basic binary image loader",
27     NULL
28   },
29   noit_load_module_image
30 };
31 struct __extended_image_data {
32   void *userdata;
33 };
34
35 static noit_hash_table loaders = NOIT_HASH_EMPTY;
36 static noit_hash_table modules = NOIT_HASH_EMPTY;
37
38 noit_module_loader_t * noit_loader_lookup(const char *name) {
39   noit_module_loader_t *loader;
40
41   if(noit_hash_retrieve(&loaders, name, strlen(name), (void **)&loader)) {
42     return loader;
43   }
44   return NULL;
45 }
46
47 noit_module_t * noit_module_lookup(const char *name) {
48   noit_module_t *module;
49
50   if(noit_hash_retrieve(&modules, name, strlen(name), (void **)&module)) {
51     return module;
52   }
53   return NULL;
54 }
55
56 static int noit_module_validate_magic(noit_image_t *obj) {
57   if (NOIT_IMAGE_MAGIC(obj) != NOIT_MODULE_MAGIC) return -1;
58   if (NOIT_IMAGE_VERSION(obj) != NOIT_MODULE_ABI_VERSION) return -1;
59   return 0;
60 }
61
62 static int noit_module_loader_validate_magic(noit_image_t *obj) {
63   if (NOIT_IMAGE_MAGIC(obj) != NOIT_LOADER_MAGIC) return -1;
64   if (NOIT_IMAGE_VERSION(obj) != NOIT_LOADER_ABI_VERSION) return -1;
65   return 0;
66 }
67
68 int noit_load_image(const char *file, const char *name,
69                     noit_hash_table *registry,
70                     int (*validate)(noit_image_t *),
71                     size_t obj_size) {
72   char module_file[PATH_MAX];
73   char *base;
74   void *dlhandle;
75   void *dlsymbol;
76   noit_image_t *obj;
77
78   if(!noit_conf_get_string(NULL, "/noit/modules/@directory", &base))
79     base = strdup("");
80
81   if(file[0] == '/')
82     strlcpy(module_file, file, sizeof(module_file));
83   else
84     snprintf(module_file, sizeof(module_file), "%s/%s.%s",
85              base, file, MODULEEXT);
86   free(base);
87
88   dlhandle = dlopen(module_file, RTLD_LAZY | RTLD_GLOBAL);
89   if(!dlhandle) {
90     noitL(noit_stderr, "Cannot open image '%s': %s\n",
91           module_file, dlerror());
92     return -1;
93   }
94
95   dlsymbol = dlsym(dlhandle, name);
96   if(!dlsymbol) {
97     noitL(noit_stderr, "Cannot find '%s' in image '%s': %s\n",
98           name, module_file, dlerror());
99     dlclose(dlhandle);
100     return -1;
101   }
102
103   if(validate(dlsymbol) == -1) {
104     noitL(noit_stderr, "I can't understand image %s\n", name);
105     dlclose(dlhandle);
106     return -1;
107   }
108
109   obj = calloc(1, obj_size);
110   memcpy(obj, dlsymbol, obj_size);
111   obj->opaque_handle = calloc(1, sizeof(struct __extended_image_data));
112
113   if(obj->onload && obj->onload(obj)) {
114     free(obj);
115     return -1;
116   }
117   noit_hash_store(registry, obj->name, strlen(obj->name), obj);
118   return 0;
119 }
120
121 static noit_module_loader_t *
122 noit_load_loader_image(noit_module_loader_t *loader,
123                        char *loader_name,
124                        noit_conf_section_t section) {
125   char loader_file[PATH_MAX];
126
127   if(!noit_conf_get_stringbuf(section, "ancestor-or-self::node()/@image",
128                               loader_file, sizeof(loader_file))) {
129     noitL(noit_stderr, "No image defined for %s\n", loader_name);
130     return NULL;
131   }
132   if(noit_load_image(loader_file, loader_name, &loaders,
133                      noit_module_loader_validate_magic,
134                      sizeof(noit_module_loader_t))) {
135     noitL(noit_stderr, "Could not load %s:%s\n", loader_file, loader_name);
136     return NULL;
137   }
138   return noit_loader_lookup(loader_name);
139 }
140
141 static noit_module_t *
142 noit_load_module_image(noit_module_loader_t *loader,
143                        char *module_name,
144                        noit_conf_section_t section) {
145   char module_file[PATH_MAX];
146
147   if(!noit_conf_get_stringbuf(section, "ancestor-or-self::node()/@image",
148                               module_file, sizeof(module_file))) {
149     noitL(noit_stderr, "No image defined for %s\n", module_name);
150     return NULL;
151   }
152   if(noit_load_image(module_file, module_name, &modules,
153                      noit_module_validate_magic, sizeof(noit_module_t))) {
154     noitL(noit_stderr, "Could not load %s:%s\n", module_file, module_name);
155     return NULL;
156   }
157   return noit_module_lookup(module_name);
158 }
159
160 void noit_module_init() {
161   noit_conf_section_t *sections;
162   int i, cnt = 0;
163
164   /* Load our module loaders */
165   sections = noit_conf_get_sections(NULL, "/noit/modules//loader", &cnt);
166   for(i=0; i<cnt; i++) {
167     char loader_name[256];
168     noit_module_loader_t *loader;
169
170     if(!noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name",
171                                 loader_name, sizeof(loader_name))) {
172       noitL(noit_stderr, "No name defined in loader stanza %d\n", i+1);
173       continue;
174     }
175     loader = noit_load_loader_image(&__noit_image_loader, loader_name,
176                                     sections[i]);
177     if(!loader) {
178       noitL(noit_stderr, "Failed to load loader %s\n", loader_name);
179       continue;
180     }
181   }
182   if(sections) free(sections);
183
184   /* Load the modules */
185   sections = noit_conf_get_sections(NULL, "/noit/modules//module", &cnt);
186   if(!sections) return;
187   for(i=0; i<cnt; i++) {
188     noit_module_loader_t *loader = &__noit_image_loader;
189     noit_hash_table *config;
190     noit_module_t *module;
191     char loader_name[256];
192     char module_name[256];
193
194     /* If no loader is specified, we should use the image loader */
195     if(!noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@name",
196                                 module_name, sizeof(module_name))) {
197       noitL(noit_stderr, "No name defined in module stanza %d\n", i+1);
198       continue;
199     }
200
201     if(noit_conf_get_stringbuf(sections[i], "ancestor-or-self::node()/@loader",
202                                 loader_name, sizeof(loader_name))) {
203       loader = noit_loader_lookup(loader_name);
204       if(!loader) {
205         noitL(noit_stderr, "No '%s' loader found.\n", loader_name);
206         continue;
207       }
208     } else {
209       strlcpy(loader_name, "image", sizeof(loader_name));
210     }
211
212     module = loader->load(loader, module_name, sections[i]);
213     if(!module) {
214       noitL(noit_stderr, "Loader '%s' failed to load '%s'.\n",
215             loader_name, module_name);
216       continue;
217     }
218     config = noit_conf_get_hash(sections[i], "config");
219     if(module->config) {
220       int rv;
221       rv = module->config(module, config);
222       if(rv == 0) {
223         /* Not an error,
224          * but the module didn't take responsibility for the config.
225          */
226         noit_hash_destroy(config, free, free);
227         free(config);
228       }
229       else if(rv < 0) {
230         noitL(noit_stderr,
231               "Configure failed on %s\n", module_name);
232         continue;
233       }
234     }
235     if(module->init && module->init(module)) {
236       noitL(noit_stderr,
237             "Initialized failed on %s\n", module_name);
238       continue;
239     }
240     noitL(noit_stderr, "Module %s successfully loaded.\n", module_name);
241   }
242   free(sections);
243 }
244
245 #define userdata_accessors(type, field) \
246 void *noit_##type##_get_userdata(noit_##type##_t *mod) { \
247   return ((struct __extended_image_data *)mod->field)->userdata; \
248 } \
249 void noit_##type##_set_userdata(noit_##type##_t *mod, void *newdata) { \
250   ((struct __extended_image_data *)mod->field)->userdata = newdata; \
251 }
252
253 userdata_accessors(image, opaque_handle)
254 userdata_accessors(module_loader, hdr.opaque_handle)
255 userdata_accessors(module, hdr.opaque_handle)
Note: See TracBrowser for help on using the browser.