51 |
63 |
52 // ok |
64 // ok |
53 return SUCCESS; |
65 return SUCCESS; |
54 } |
66 } |
55 |
67 |
56 err_t module_load (struct modules *modules, struct module **module_ptr, const struct module_info *info, struct error_info *err) |
68 /** |
|
69 * XXX: ugly function to format to a dynamically allocated string |
|
70 */ |
|
71 char *strfmt (const char *fmt, ...) |
|
72 { |
|
73 va_list vargs; |
|
74 size_t len; |
|
75 char *buf; |
|
76 |
|
77 // figure out the length of the resulting string |
|
78 va_start(vargs, fmt); |
|
79 |
|
80 len = vsnprintf(NULL, 0, fmt, vargs) + 1; |
|
81 |
|
82 va_end(vargs); |
|
83 |
|
84 // malloc |
|
85 if ((buf = malloc(len)) == NULL) |
|
86 return NULL; |
|
87 |
|
88 // format |
|
89 va_start(vargs, fmt); |
|
90 |
|
91 vsnprintf(buf, len, fmt, vargs); |
|
92 |
|
93 va_end(vargs); |
|
94 |
|
95 // ok |
|
96 return buf; |
|
97 } |
|
98 |
|
99 /** |
|
100 * Looks up a module's path by name, returning a dynamically allocated string with the path on success |
|
101 */ |
|
102 static char* module_find (struct modules *modules, struct module_info *info, struct error_info *err) |
|
103 { |
|
104 char *path = NULL; |
|
105 |
|
106 // build the path... |
|
107 if ((path = strfmt("%s/mod_%s.so", modules->path, info->name)) == NULL) |
|
108 JUMP_SET_ERROR(err, ERR_STRDUP); |
|
109 |
|
110 // exists and readable? |
|
111 if (access(path, R_OK)) |
|
112 // XXX: this doesn't contain the path... |
|
113 JUMP_SET_ERROR_STR(err, ERR_MODULE_PATH, "module not found in search path"); |
|
114 |
|
115 // ok |
|
116 return path; |
|
117 |
|
118 error: |
|
119 // release the dynamically allocated path |
|
120 free(path); |
|
121 |
|
122 return NULL; |
|
123 } |
|
124 |
|
125 err_t module_load (struct modules *modules, struct module **module_ptr, const struct module_info *_info, struct error_info *err) |
57 { |
126 { |
58 struct module *module; |
127 struct module *module; |
59 |
128 |
60 // validate the module name |
129 // validate the module name |
61 if (strlen(info->name) > MODULE_NAME_MAX) |
130 if (strlen(_info->name) > MODULE_NAME_MAX) |
62 return SET_ERROR(err, ERR_MODULE_NAME); |
131 return SET_ERROR(err, ERR_MODULE_NAME); |
63 |
132 |
|
133 // already open with the same name? |
|
134 if (module_get(modules, _info->name)) |
|
135 return SET_ERROR(err, ERR_MODULE_DUP); |
|
136 |
64 // alloc |
137 // alloc |
65 if ((module = calloc(1, sizeof(*module))) == NULL) |
138 if ((module = calloc(1, sizeof(*module))) == NULL) |
66 return SET_ERROR(err, ERR_CALLOC); |
139 return SET_ERROR(err, ERR_CALLOC); |
67 |
140 |
68 // store |
141 // store |
69 module->info = *info; |
142 module->info = *_info; |
70 module->modules = modules; |
143 module->modules = modules; |
|
144 |
|
145 // add to modules list |
|
146 TAILQ_INSERT_TAIL(&modules->list, module, modules_list); |
|
147 |
|
148 // lookup path? |
|
149 if (!module->info.path) { |
|
150 // have a search path? |
|
151 if (!modules->path) |
|
152 JUMP_SET_ERROR_STR(err, ERR_MODULE_PATH, "no module search path defined"); |
|
153 |
|
154 // try and resolve the path automatically |
|
155 if ((module->path_buf = module_find(modules, &module->info, err)) == NULL) |
|
156 goto error; |
|
157 |
|
158 // use that path |
|
159 module->info.path = module->path_buf; |
|
160 } |
71 |
161 |
72 // clear dlerrors |
162 // clear dlerrors |
73 (void) dlerror(); |
163 (void) dlerror(); |
74 |
164 |
75 // load it |
165 // load it |
76 if ((module->handle = dlopen(info->path, RTLD_NOW)) == NULL) |
166 if ((module->handle = dlopen(module->info.path, RTLD_NOW)) == NULL) |
77 JUMP_SET_ERROR_STR(err, ERR_MODULE_OPEN, dlerror()); |
167 JUMP_SET_ERROR_STR(err, ERR_MODULE_OPEN, dlerror()); |
78 |
168 |
79 // load the funcs symbol |
169 // load the funcs symbol |
80 if ((ERROR_CODE(err) = module_symbol(module, (void **) &module->desc, "module"))) |
170 if ((ERROR_CODE(err) = module_symbol(module, (void **) &module->desc, "module"))) |
81 JUMP_SET_ERROR_STR(err, ERROR_CODE(err), dlerror()); |
171 JUMP_SET_ERROR_STR(err, ERROR_CODE(err), dlerror()); |
82 |
172 |
83 // call the init func |
173 // call the init func |
84 if ((module->desc->init(modules->nexus, &module->ctx, err))) |
174 if ((module->desc->init(modules->nexus, &module->ctx, err))) |
85 goto error; |
175 goto error; |
86 |
176 |
87 // add to modules list |
|
88 TAILQ_INSERT_TAIL(&modules->list, module, modules_list); |
|
89 |
|
90 // ok |
177 // ok |
91 if (module_ptr) |
178 if (module_ptr) |
92 *module_ptr = module; |
179 *module_ptr = module; |
93 |
180 |
94 return SUCCESS; |
181 return SUCCESS; |
95 |
182 |
96 error: |
183 error: |
97 // XXX: cleanup |
184 // cleanup |
98 free(module); |
185 module_destroy(module); |
99 |
186 |
100 return ERROR_CODE(err); |
187 return ERROR_CODE(err); |
101 } |
188 } |
102 |
189 |
103 struct module* module_get (struct modules *modules, const char *name) |
190 struct module* module_get (struct modules *modules, const char *name) |
170 { |
257 { |
171 // remove from modules list |
258 // remove from modules list |
172 TAILQ_REMOVE(&module->modules->list, module, modules_list); |
259 TAILQ_REMOVE(&module->modules->list, module, modules_list); |
173 |
260 |
174 // unload the dl handle |
261 // unload the dl handle |
175 if (dlclose(module->handle)) |
262 if (module->handle && dlclose(module->handle)) |
176 log_error("dlclose(%s): %s", module->info.name, dlerror()); |
263 log_error("dlclose(%s): %s", module->info.name, dlerror()); |
177 |
264 |
|
265 // release the path buf, if any |
|
266 free(module->path_buf); |
|
267 |
178 // free the module info |
268 // free the module info |
179 free(module); |
269 free(module); |
180 } |
270 } |
181 |
271 |
182 err_t modules_unload (struct modules *modules) |
272 err_t modules_unload (struct modules *modules) |