ViewVC Help
View File | Revision Log | Show Annotations | View Changeset | Root Listing
root/svn/vendor/ircservices-5.1.24/modules.c
Revision: 3389
Committed: Fri Apr 25 14:12:15 2014 UTC (11 years, 4 months ago) by michael
Content type: text/x-csrc
File size: 31051 byte(s)
Log Message:
- Imported ircservices-5.1.24

File Contents

# Content
1 /* Module support.
2 *
3 * IRC Services is copyright (c) 1996-2009 Andrew Church.
4 * E-mail: <achurch@achurch.org>
5 * Parts written by Andrew Kempe and others.
6 * This program is free but copyrighted software; see the file GPL.txt for
7 * details.
8 */
9
10 #include "services.h"
11 #include "modules.h"
12 #include "conffile.h"
13 #undef use_module
14 #undef unuse_module
15
16 #if !STATIC_MODULES
17 # include <dlfcn.h>
18 #endif
19
20 /*************************************************************************/
21
22 /* Internal structure for callbacks. */
23 typedef struct callbackinfo_ CallbackInfo;
24 struct callbackinfo_ {
25 char *name;
26 int calling; /* used by {call,remove}_callback() for safe callback
27 * removal from inside the callback */
28 struct {
29 callback_t func;
30 const Module *adder;
31 int pri;
32 } *funcs;
33 int funcs_count;
34 };
35
36 /* Structure for module data. */
37 struct Module_ {
38 Module *next, *prev;
39 char *name; /* Module name (path passed to load_module())*/
40 ConfigDirective *modconfig; /* `module_config' in this module */
41 Module ***this_module_pptr; /* `_this_module_ptr' in this module */
42 const int32 *module_version_ptr; /* `module_version' in this module */
43 void *dllhandle; /* Handle used by dynamic linker */
44 CallbackInfo *callbacks;
45 int callbacks_count;
46 const Module **users; /* Array of module's users (use_module()) */
47 int users_count;
48 };
49
50
51 /* Module data for Services core. */
52 static Module coremodule = {.name = "core"};
53
54
55 /* Global list of modules. */
56 static Module *modulelist = &coremodule;
57
58
59 /* Callbacks for loading, unloading, and reconfiguring modules. */
60 static int cb_load_module = -1;
61 static int cb_unload_module = -1;
62 static int cb_reconfigure = -1;
63
64
65 /*************************************************************************/
66
67 #if STATIC_MODULES
68
69 /* Structure for a module symbol. */
70 struct modsym {
71 const char *symname;
72 void *value;
73 };
74
75 /* Static module information (from modules/modules.a): */
76 struct modinfo {
77 const char *modname;
78 struct modsym *modsyms;
79 };
80 extern struct modinfo modlist[];
81
82 #else /* !STATIC_MODULES */
83
84 static void *program_handle; /* Handle for the main program */
85
86 #endif /* STATIC_MODULES */
87
88 /*************************************************************************/
89
90 /* Internal routine declarations: */
91
92 static Module *internal_load_module(const char *modulename);
93 static int internal_init_module(Module *module);
94 static int internal_unload_module(Module *module, int shutdown);
95
96 /*************************************************************************/
97
98 /* Translate the NULL module to &coremodule, and ensure that any given
99 * module is in fact on the module list, aborting the function otherwise.
100 * Call as:
101 * VALIDATE_MOD(module)
102 * or
103 * VALIDATE_MOD(module, return_value)
104 * where `module' is a variable holding a module handle.
105 */
106
107 #define VALIDATE_MOD(__m,...) do { \
108 if (!__m) { \
109 __m = &coremodule; \
110 } else { \
111 Module *__tmp; \
112 LIST_FOREACH (__tmp, modulelist) { \
113 if (__tmp == __m) \
114 break; \
115 } \
116 if (!__tmp) { \
117 log("%s(): module %p not on module list", __FUNCTION__, __m); \
118 return __VA_ARGS__; \
119 } \
120 } \
121 } while (0)
122
123 /*************************************************************************/
124 /********************* Initialization and cleanup ************************/
125 /*************************************************************************/
126
127 int modules_init(int ac, char **av)
128 {
129 #if !STATIC_MODULES
130 program_handle = dlopen(NULL, 0);
131 #endif
132 cb_load_module = register_callback("load module");
133 cb_unload_module = register_callback("unload module");
134 cb_reconfigure = register_callback("reconfigure");
135 if (cb_load_module < 0 || cb_unload_module < 0 || cb_reconfigure < 0) {
136 log("modules_init: register_callback() failed\n");
137 return 0;
138 }
139 return 1;
140 }
141
142 /*************************************************************************/
143
144 void modules_cleanup(void)
145 {
146 int i;
147
148 unload_all_modules();
149 unregister_callback(cb_reconfigure);
150 unregister_callback(cb_unload_module);
151 unregister_callback(cb_load_module);
152 ARRAY_FOREACH(i, coremodule.callbacks) {
153 if (coremodule.callbacks[i].name) {
154 log("modules: Core forgot to unregister callback `%s'",
155 coremodule.callbacks[i].name);
156 free(coremodule.callbacks[i].name);
157 free(coremodule.callbacks[i].funcs);
158 }
159 }
160 free(coremodule.callbacks);
161 }
162
163 /*************************************************************************/
164
165 void unload_all_modules(void)
166 {
167 /* Normally it would be sufficient to iterate through the module list,
168 * since new modules are always inserted at the front of the list, but
169 * it is possible for an older module to lock a newer module via the
170 * "load module" callback, resulting in unload failures if that simple
171 * method was used. Instead, we repeatedly search the module list for
172 * the first unloadable module (a module that is not the core module
173 * and is not locked), unload that module, and repeat until no
174 * unloadable modules are left. (In theory, since a module's locks are
175 * forcibly when the module is unloaded, this should only leave the
176 * core module, but we check anyway just to be safe.) */
177
178 for (;;) {
179 Module *mod;
180 LIST_FOREACH (mod, modulelist) {
181 if (strcmp(mod->name, "core") != 0) {
182 int i;
183 ARRAY_FOREACH (i, mod->users) {
184 if (mod->users[i] != mod)
185 break;
186 }
187 if (i >= mod->users_count) {
188 /* This module has no users (except possibly itself),
189 * so unload it */
190 break;
191 }
192 }
193 }
194 if (!mod)
195 break;
196 if (!internal_unload_module(mod, 1)) {
197 log("modules: Failed to unload `%s' on exit", mod->name);
198 /* Unlink it anyway, but don't free the structure to avoid
199 * segfaults in the module. This is an impossible case
200 * anyway, so we don't worry about the leak. */
201 LIST_REMOVE(mod, modulelist);
202 }
203 }
204
205 if (!modulelist) {
206 log("modules: BUG: core module got removed from module list during"
207 " shutdown!");
208 } else if (modulelist != &coremodule || modulelist->next != NULL) {
209 Module *mod;
210 log("modules: BUG: failed to unload some modules during shutdown"
211 " (circular lock?)");
212 LIST_FOREACH (mod, modulelist) {
213 if (strcmp(mod->name, "core") != 0) {
214 log("modules: -- module %s not unloaded", mod->name);
215 }
216 }
217 }
218 }
219
220 /*************************************************************************/
221 /*********************** Low-level module routines ***********************/
222 /*************************************************************************/
223
224 /* These low-level routines take care of all changes in processing with
225 * regard to dynamic vs. static modules and different platforms. */
226
227 /* Common variables: */
228
229 #if STATIC_MODULES
230 static const char *dl_last_error;
231 #endif
232
233 /*************************************************************************/
234
235 /* Low-level routine to open a module and return a handle. */
236
237 static void *my_dlopen(const char *name)
238 {
239 #if !STATIC_MODULES
240
241 char pathname[PATH_MAX+1];
242 snprintf(pathname, sizeof(pathname), "%s/modules/%s.so",
243 services_dir, name);
244 return dlopen(pathname, RTLD_NOW | RTLD_GLOBAL);
245
246 #else /* STATIC_MODULES */
247
248 int i;
249
250 for (i = 0; modlist[i].modname; i++) {
251 if (strcmp(modlist[i].modname, name) == 0)
252 break;
253 }
254 if (!modlist[i].modname) {
255 dl_last_error = "Module not found";
256 return NULL;
257 }
258 return &modlist[i];
259
260 #endif /* STATIC_MODULES */
261 } /* my_dlopen() */
262
263 /*************************************************************************/
264
265 /* Low-level routine to close a module. */
266
267 static void my_dlclose(void *handle)
268 {
269 #if !STATIC_MODULES
270
271 dlclose(handle);
272
273 #else /* STATIC_MODULES */
274
275 /* nothing */
276
277 #endif /* STATIC_MODULES */
278 } /* my_dlclose() */
279
280 /*************************************************************************/
281
282 /* Low-level routine to retrieve a symbol from a module given its handle. */
283
284 static void *my_dlsym(void *handle, const char *symname)
285 {
286 #if !STATIC_MODULES
287
288 # if SYMS_NEED_UNDERSCORES
289 char buf[256];
290 if (strlen(symname) > sizeof(buf)-2) { /* too long for buffer */
291 log("modules: symbol name too long in my_dlsym(): %s", symname);
292 return NULL;
293 }
294 snprintf(buf, sizeof(buf), "_%s", symname);
295 symname = buf;
296 # endif
297 if (handle) {
298 return dlsym(handle, symname);
299 } else {
300 Module *mod;
301 void *ptr;
302 LIST_FOREACH (mod, modulelist) {
303 ptr = dlsym(mod->dllhandle?mod->dllhandle:program_handle, symname);
304 if (ptr)
305 return ptr;
306 }
307 return NULL;
308 }
309
310 #else /* STATIC_MODULES */
311
312 int i;
313
314 if (handle) {
315 struct modsym *syms = ((struct modinfo *)handle)->modsyms;
316 for (i = 0; syms[i].symname; i++) {
317 if (strcmp(syms[i].symname, symname) == 0)
318 break;
319 }
320 if (!syms[i].symname) {
321 dl_last_error = "Symbol not found";
322 return NULL;
323 }
324 return syms[i].value;
325 } else {
326 const char *save_dl_last_error = dl_last_error;
327 for (i = 0; modlist[i].modname; i++) {
328 void *value = my_dlsym(&modlist[i], symname);
329 if (value) {
330 dl_last_error = save_dl_last_error;
331 return value;
332 }
333 }
334 dl_last_error = "Symbol not found";
335 return NULL;
336 }
337
338 #endif /* STATIC_MODULES */
339 } /* my_dlsym() */
340
341 /*************************************************************************/
342
343 /* Low-level routine to return the error message (if any) from the previous
344 * call. */
345
346 static const char *my_dlerror(void)
347 {
348 #if !STATIC_MODULES
349
350 return dlerror();
351
352 #else /* STATIC_MODULES */
353
354 const char *str = dl_last_error;
355 dl_last_error = NULL;
356 return str;
357
358 #endif /* STATIC_MODULES */
359 } /* my_dlerror() */
360
361 /*************************************************************************/
362 /************************ Module-level functions *************************/
363 /*************************************************************************/
364
365 /* Load a new module and return the Module pointer, or NULL on error.
366 * (External interface to the above functions.)
367 */
368
369 Module *load_module(const char *modulename)
370 {
371 Module *module;
372
373
374 if (!modulename) {
375 log("load_module(): modulename is NULL!");
376 return NULL;
377 }
378
379 log_debug(1, "Loading module `%s'", modulename);
380
381 module = internal_load_module(modulename);
382 if (!module)
383 return NULL;
384 LIST_INSERT(module, modulelist);
385
386 if (!configure(module->name, module->modconfig,
387 CONFIGURE_READ | CONFIGURE_SET)) {
388 log("modules: configure() failed for %s", modulename);
389 goto fail;
390 }
391
392 if (!internal_init_module(module)) {
393 log("modules: init_module() failed for %s", modulename);
394 deconfigure(module->modconfig);
395 goto fail;
396 }
397
398 log_debug(1, "Successfully loaded module `%s'", modulename);
399 call_callback_2(cb_load_module, module, module->name);
400
401 /* This is a REALLY STUPID HACK to ensure protocol modules are loaded
402 * first--but hey, it works! */
403 if (protocol_features & PF_UNSET) {
404 log("FATAL: load_module(): A protocol module must be loaded first!");
405 unload_module(module);
406 return NULL;
407 }
408
409 return module;
410
411 fail:
412 free(module->name);
413 my_dlclose(module->dllhandle);
414 LIST_REMOVE(module, modulelist);
415 free(module);
416 return NULL;
417 }
418
419 /************************************/
420
421 /* Internal routine to load a module. Returns the module pointer or NULL
422 * on error.
423 */
424
425 static Module *internal_load_module(const char *modulename)
426 {
427 void *handle;
428 Module *module, *mptr;
429 int32 *verptr;
430 Module ***thisptr;
431 ConfigDirective *confptr;
432
433 if (strstr(modulename, "../")) {
434 log("modules: Attempt to load bad module name: %s", modulename);
435 goto err_return;
436 }
437 LIST_SEARCH(modulelist, name, modulename, strcmp, mptr);
438 if (mptr) {
439 log("modules: Attempt to load module `%s' twice", modulename);
440 goto err_return;
441 }
442
443 handle = my_dlopen(modulename);
444 if (!handle) {
445 const char *error = my_dlerror();
446 if (!error)
447 error = "Unknown error";
448 log("modules: Unable to load module `%s': %s", modulename, error);
449 goto err_return;
450 }
451
452 module = scalloc(sizeof(*module), 1);
453 module->dllhandle = handle;
454 module->name = sstrdup(modulename);
455
456 thisptr = NULL;
457 if (check_module_symbol(module, "_this_module_ptr", (void **)&thisptr,
458 NULL)){
459 #if !defined(STATIC_MODULES)
460 /* When using dynamic linking, the above may return the first
461 * instance of `_this_module_ptr' found in _any_ module (though
462 * giving priority to the given module), so we need to check if
463 * we've seen this address before. With static linking, the result
464 * will be NULL if the symbol does not exist in this specific
465 * module, so the extra check is unnecessary. */
466 LIST_SEARCH_SCALAR(modulelist, this_module_pptr, thisptr, mptr);
467 if (mptr)
468 thisptr = NULL;
469 #endif
470 }
471 if (!thisptr) {
472 log("modules: Unable to load module `%s': No `_this_module_ptr' symbol"
473 " found", modulename);
474 goto err_freemod;
475 }
476 module->this_module_pptr = thisptr;
477 **thisptr = module;
478
479 verptr = NULL; /* as above */
480 if (check_module_symbol(module, "module_version", (void **)&verptr, NULL)){
481 #if !defined(STATIC_MODULES)
482 LIST_SEARCH_SCALAR(modulelist, module_version_ptr, verptr, mptr);
483 if (mptr)
484 verptr = NULL;
485 #endif
486 }
487 if (!verptr) {
488 log("modules: Unable to load module `%s': No `module_version'"
489 " symbol found", modulename);
490 goto err_freemod;
491 } else if (*verptr != MODULE_VERSION_CODE) {
492 log("modules: Unable to load module `%s': Version mismatch"
493 " (module version = %08X, core version = %08X)",
494 modulename, *verptr, MODULE_VERSION_CODE);
495 goto err_freemod;
496 }
497 module->module_version_ptr = verptr;
498
499 confptr = NULL; /* as above */
500 if (check_module_symbol(module, "module_config", (void **)&confptr, NULL)){
501 #if !defined(STATIC_MODULES)
502 LIST_SEARCH_SCALAR(modulelist, modconfig, confptr, mptr);
503 if (mptr)
504 confptr = NULL;
505 #endif
506 }
507 module->modconfig = confptr;
508
509 return module;
510
511 err_freemod:
512 free(module->name);
513 free(module);
514 my_dlclose(handle);
515 err_return:
516 return NULL;
517 }
518
519 /************************************/
520
521 /* Initialize a module. Return the module's init_module() return value, or
522 * 1 if the module does not have an init_module() function.
523 */
524
525 static int internal_init_module(Module *module)
526 {
527 int (*initfunc)(void);
528
529 initfunc = get_module_symbol(module, "init_module");
530 if (initfunc)
531 return initfunc();
532 else
533 return 1;
534 }
535
536 /*************************************************************************/
537
538 /* Remove a module from memory. Return nonzero on success, zero on
539 * failure.
540 */
541
542 int unload_module(Module *module)
543 {
544 return internal_unload_module(module, 0);
545 }
546
547 /************************************/
548
549 /* Internal implementation of unload_module(), taking an additional
550 * parameter indicating whether the unload is due to Services shutting down
551 * or not.
552 */
553
554 static int internal_unload_module(Module *module, int shutdown)
555 {
556 int (*exit_module)(int shutdown);
557 Module *tmp;
558 int i;
559
560
561 if (!module) {
562 log("unload_module(): module is NULL!");
563 return 0;
564 }
565
566 if (module->users_count > 0) {
567 log("modules: Attempt to unload in-use module `%s' (in use by %s%s)",
568 module->name, module->users[0]->name,
569 module->users_count>1 ? " and others" : "");
570 return 0;
571 }
572
573 log_debug(1, "Unloading module `%s'", module->name);
574
575 /* Call the module's exit routine */
576 exit_module = get_module_symbol(module, "exit_module");
577 if (exit_module && !(*exit_module)(shutdown)) {
578 if (shutdown) {
579 log("modules: exit_module() for module `%s' returned zero on"
580 " shutdown, unloading module anyway", module->name);
581 } else {
582 return 0;
583 }
584 }
585
586 /* Remove the module from the global module list, ensuring that no
587 * new callbacks or the like can be added while we unload it */
588 LIST_REMOVE(module, modulelist);
589
590 /* Ensure that callbacks and use_module() calls are properly undone */
591 LIST_FOREACH (tmp, modulelist) {
592 ARRAY_FOREACH (i, tmp->users) {
593 if (tmp->users[i] == module) {
594 log("modules: Module `%s' forgot to unuse_module() for"
595 " module `%s'", module->name, tmp->name);
596 ARRAY_REMOVE(tmp->users, i);
597 i--;
598 }
599 }
600 ARRAY_FOREACH (i, tmp->callbacks) {
601 int j;
602 /* Don't warn for callbacks that couldn't have been removed
603 * because the callback was in use (e.g. for shutting down
604 * after a crash) */
605 if (tmp->callbacks[i].calling)
606 continue;
607 ARRAY_FOREACH (j, tmp->callbacks[i].funcs) {
608 if (tmp->callbacks[i].funcs[j].adder == module) {
609 log("modules: Module `%s' forgot to remove callback"
610 " `%s' from module `%s'", module->name,
611 tmp->callbacks[i].name, tmp->name);
612 ARRAY_REMOVE(tmp->callbacks[i].funcs, j);
613 j--;
614 }
615 }
616 }
617 }
618 ARRAY_FOREACH (i, module->callbacks) {
619 if (module->callbacks[i].name) {
620 log("modules: Module `%s' forgot to unregister callback `%s'",
621 module->name, module->callbacks[i].name);
622 free(module->callbacks[i].name);
623 free(module->callbacks[i].funcs);
624 }
625 }
626 free(module->callbacks);
627
628 /* Clean up and free the module data */
629 call_callback_1(cb_unload_module, module);
630 deconfigure(module->modconfig);
631 free(module->name);
632 my_dlclose(module->dllhandle);
633 free(module);
634
635 return 1;
636 }
637
638 /*************************************************************************/
639
640 /* Return the Module pointer for the named module, or NULL if no such
641 * module exists.
642 */
643
644 Module *find_module(const char *modulename)
645 {
646 Module *result;
647
648 if (!modulename) {
649 log("find_module(): modulename is NULL!");
650 return NULL;
651 }
652 LIST_SEARCH(modulelist, name, modulename, strcmp, result);
653 return result;
654 }
655
656 /*************************************************************************/
657
658 /* Increment the use count for the given module. A module cannot be
659 * unloaded while its use count is nonzero.
660 */
661
662 static int use_module_loopcheck(const Module *module, const Module *check)
663 {
664 /* Return whether `module' is used by `check' (self-references are
665 * ignored). */
666
667 int i;
668
669 ARRAY_FOREACH (i, module->users) {
670 if (module->users[i] != module) {
671 if (module->users[i] == check
672 || use_module_loopcheck(module->users[i], check))
673 return 1;
674 }
675 }
676 return 0;
677 }
678
679 void _use_module(Module *module, const Module *caller)
680 {
681 VALIDATE_MOD(module);
682 VALIDATE_MOD(caller);
683 if (module == caller) {
684 log("modules: BUG: Module `%s' called use_module() for itself!",
685 module->name);
686 return;
687 }
688 if (use_module_loopcheck(caller, module)) {
689 log("modules: BUG: use_module loop detected (called by `%s' for `%s')",
690 caller->name, module->name);
691 return;
692 }
693 ARRAY_EXTEND(module->users);
694 module->users[module->users_count-1] = caller;
695 }
696
697 /*************************************************************************/
698
699 /* Decrement the use count for the given module. `module' may be NULL, in
700 * which case this routine does nothing.
701 */
702
703 void _unuse_module(Module *module, const Module *caller)
704 {
705 int i;
706
707 if (!module)
708 return;
709 VALIDATE_MOD(module);
710 VALIDATE_MOD(caller);
711 if (module == caller) {
712 log("modules: BUG: Module `%s' called unuse_module() for itself!",
713 module->name);
714 return;
715 }
716 if (module->users_count == 0) {
717 log("modules: BUG: trying to unuse module `%s' with use count 0"
718 " from module `%s'", module->name, caller->name);
719 return;
720 }
721 ARRAY_SEARCH_PLAIN_SCALAR(module->users, caller, i);
722 if (i >= module->users_count) {
723 log("modules: BUG: trying to unuse module `%s' from module `%s' but"
724 " caller not found in user list!", module->name, caller->name);
725 return;
726 }
727 ARRAY_REMOVE(module->users, i);
728 }
729
730 /*************************************************************************/
731
732 /* Reconfigure all modules. The "reconfigure" callback is called with an
733 * `int' parameter of 0 before reconfiguration and 1 after. Returns 1 on
734 * success, 0 on failure (on failure, all modules' configuration data will
735 * be left alone).
736 */
737
738 int reconfigure_modules(void)
739 {
740 Module *mod;
741
742 call_callback_1(cb_reconfigure, 0);
743 LIST_FOREACH (mod, modulelist) {
744 if (!configure(mod->name, mod->modconfig, CONFIGURE_READ))
745 return 0;
746 }
747 LIST_FOREACH (mod, modulelist)
748 configure(mod->name, mod->modconfig, CONFIGURE_SET);
749 call_callback_1(cb_reconfigure, 1);
750 return 1;
751 }
752
753 /*************************************************************************/
754 /****************** Module symbol/information retrieval ******************/
755 /*************************************************************************/
756
757 /* Retrieve the value of the named symbol in the given module. Return NULL
758 * if no such symbol exists. Note that this function should not be used
759 * for symbols whose value might be NULL, because there is no way to
760 * distinguish a symbol value of NULL from an error return. For such
761 * symbols, or for cases where a symbol might legitimately not exist and
762 * no error should be printed for nonexistence, use check_module_symbol().
763 */
764
765 void *_get_module_symbol(Module *module, const char *symname,
766 const Module *caller)
767 {
768 void *value;
769
770 if (!check_module_symbol(module, symname, &value, NULL)) {
771 if (module) {
772 log("%s: Unable to resolve symbol `%s' in module `%s'",
773 get_module_name(caller), symname, get_module_name(module));
774 } else {
775 log("%s: Unable to resolve symbol `%s'",
776 get_module_name(caller), symname);
777 }
778 return NULL;
779 }
780 return value;
781 }
782
783 /*************************************************************************/
784
785 /* Check whether the given symbol exists in the given module; return 1 if
786 * so, 0 otherwise. If `resultptr' is non-NULL and the symbol exists, the
787 * value is stored in the variable it points to. If `errorptr' is non-NULL
788 * and the symbol does not exist, a human-readable error message is stored
789 * in the variable it points to.
790 */
791
792 int check_module_symbol(Module *module, const char *symname,
793 void **resultptr, const char **errorptr)
794 {
795 void *value;
796 const char *error;
797
798 (void) my_dlerror(); /* clear any previous error */
799 value = my_dlsym(module ? module->dllhandle : NULL, symname);
800 error = my_dlerror();
801 if (error) {
802 if (errorptr)
803 *errorptr = error;
804 return 0;
805 } else {
806 if (resultptr)
807 *resultptr = value;
808 return 1;
809 }
810 }
811
812 /*************************************************************************/
813
814 /* Retrieve the name of the given module. If NULL is given, returns the
815 * string "core".
816 */
817
818 const char *get_module_name(const Module *module)
819 {
820 return module ? module->name : "core";
821 }
822
823 /*************************************************************************/
824 /********************** Callback-related functions ***********************/
825 /*************************************************************************/
826
827 /* Local function to look up a callback for a module. Returns NULL if not
828 * found.
829 */
830
831 static CallbackInfo *find_callback(Module *module, const char *name)
832 {
833 int i;
834
835 ARRAY_FOREACH (i, module->callbacks) {
836 if (module->callbacks[i].name
837 && strcmp(module->callbacks[i].name,name) == 0)
838 break;
839 }
840 if (i == module->callbacks_count)
841 return NULL;
842 return &module->callbacks[i];
843 }
844
845 /*************************************************************************/
846
847 /* Register a new callback. "module" is the calling module's own Module
848 * pointer, or NULL for core Services callbacks (this is set by the
849 * register_callback() macro). Return the callback identifier (a
850 * nonnegative integer) or -1 on error.
851 */
852
853 int _register_callback(Module *module, const char *name)
854 {
855 int i;
856
857 log_debug(2, "register_callback(%s, \"%s\")",
858 module ? module->name : "core", name);
859 VALIDATE_MOD(module, -1);
860 if (find_callback(module, name)) {
861 log("BUG: register_callback(%s,\"%s\"): callback already registered",
862 module ? module->name : "core", name);
863 return -1;
864 }
865 i = module->callbacks_count;
866 ARRAY_EXTEND(module->callbacks);
867 module->callbacks[i].name = sstrdup(name);
868 module->callbacks[i].calling = 0;
869 module->callbacks[i].funcs_count = 0;
870 module->callbacks[i].funcs = NULL;
871 return i;
872 }
873
874 /*************************************************************************/
875
876 /* Call all functions hooked into a callback. Return 1 if a callback
877 * returned nonzero, 0 if all callbacks returned zero, or -1 on error.
878 */
879
880 int _call_callback_5(Module *module, int id, void *arg1, void *arg2,
881 void *arg3, void *arg4, void *arg5)
882 {
883 CallbackInfo *cl;
884 int res = 0;
885 int i;
886
887 VALIDATE_MOD(module, -1);
888 if (id < 0 || id >= module->callbacks_count)
889 return -1;
890 cl = &module->callbacks[id];
891 cl->calling = 1;
892 ARRAY_FOREACH (i, cl->funcs) {
893 res = cl->funcs[i].func(arg1, arg2, arg3, arg4, arg5);
894 if (res != 0)
895 break;
896 }
897 if (cl->calling == 2) { /* flag indicating some callbacks were removed */
898 ARRAY_FOREACH (i, cl->funcs) {
899 if (!cl->funcs[i].func) {
900 ARRAY_REMOVE(cl->funcs, i);
901 i--;
902 }
903 }
904 }
905 cl->calling = 0;
906 return res;
907 }
908
909 /*************************************************************************/
910
911 /* Delete a callback. */
912
913 int _unregister_callback(Module *module, int id)
914 {
915 CallbackInfo *cl;
916
917 VALIDATE_MOD(module, 0);
918 log_debug(2, "unregister_callback(%s, %d)", module->name, id);
919 if (id < 0 || id >= module->callbacks_count) {
920 log("unregister_callback(): BUG: invalid callback ID %d for module"
921 " `%s'", id, module->name);
922 return 0;
923 }
924 cl = &module->callbacks[id];
925 if (!cl->name) {
926 log("unregister_callback(): BUG: callback ID %d for module `%s'"
927 " is unused (double unregister?)", id, module->name);
928 return 0;
929 }
930 free(cl->funcs);
931 free(cl->name);
932 cl->funcs = NULL;
933 cl->name = NULL;
934 return 1;
935 }
936
937 /*************************************************************************/
938
939 /* Add (hook) a function into to a callback with the given priority (higher
940 * priority value = called sooner). Callbacks with the same priority are
941 * called in the order they were added.
942 */
943
944 int _add_callback_pri(Module *module, const char *name, callback_t callback,
945 int priority, const Module *caller)
946 {
947 CallbackInfo *cl;
948 int n;
949
950 log_debug(2, "add_callback_pri(%s, \"%s\", %p, %d)",
951 module ? module->name : "core", name ? name : "(null)",
952 callback, priority);
953 VALIDATE_MOD(module, 0);
954 VALIDATE_MOD(caller, 0);
955 cl = find_callback(module, name);
956 if (!cl) {
957 log_debug(2, "-- callback not found");
958 return 0;
959 }
960 if (priority < CBPRI_MIN || priority > CBPRI_MAX) {
961 log("add_callback_pri(): priority (%d) out of range for callback"
962 " `%s' in module `%s'",
963 priority, name, module ? module->name : "core");
964 return 0;
965 }
966 ARRAY_FOREACH (n, cl->funcs) {
967 if (cl->funcs[n].pri < priority)
968 break;
969 }
970 ARRAY_INSERT(cl->funcs, n);
971 cl->funcs[n].func = callback;
972 cl->funcs[n].adder = caller;
973 cl->funcs[n].pri = priority;
974 return 1;
975 }
976
977 /*************************************************************************/
978
979 /* Remove (unhook) a function from a callback. */
980 int _remove_callback(Module *module, const char *name, callback_t callback,
981 const Module *caller)
982 {
983 CallbackInfo *cl;
984 int index;
985
986 log_debug(2, "remove_callback(%s, \"%s\", %p)",
987 module ? module->name : "core", name, callback);
988 VALIDATE_MOD(module, 0);
989 VALIDATE_MOD(caller, 0);
990 cl = find_callback(module, name);
991 if (!cl)
992 return 0;
993 ARRAY_SEARCH_SCALAR(cl->funcs, func, callback, index);
994 if (index == cl->funcs_count)
995 return 0;
996 if (cl->funcs[index].adder != caller) {
997 log("remove_callback(%s, \"%s\"): BUG: caller `%s' tried to remove"
998 " callback %p added by different module `%s'!",
999 get_module_name(module), name, get_module_name(caller), callback,
1000 get_module_name(cl->funcs[index].adder));
1001 return 0;
1002 }
1003 if (cl->calling) {
1004 cl->funcs[index].func = NULL;
1005 cl->calling = 2; /* flag to call_callback() indicating CB removed */
1006 } else {
1007 ARRAY_REMOVE(cl->funcs, index);
1008 }
1009 return 1;
1010 }
1011
1012 /*************************************************************************/
1013
1014 /*
1015 * Local variables:
1016 * c-file-style: "stroustrup"
1017 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
1018 * indent-tabs-mode: nil
1019 * End:
1020 *
1021 * vim: expandtab shiftwidth=4:
1022 */