]> jfr.im git - irc/rqf/shadowircd.git/blob - src/modules.c
DubString -> rb_strdup
[irc/rqf/shadowircd.git] / src / modules.c
1 /*
2 * ircd-ratbox: A slightly useful ircd.
3 * modules.c: A module loader.
4 *
5 * Copyright (C) 1990 Jarkko Oikarinen and University of Oulu, Co Center
6 * Copyright (C) 1996-2002 Hybrid Development Team
7 * Copyright (C) 2002-2005 ircd-ratbox development team
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 * USA
23 *
24 * $Id: modules.c 3161 2007-01-25 07:23:01Z nenolod $
25 */
26
27 #include "stdinc.h"
28
29
30 #include "modules.h"
31 #include "s_log.h"
32 #include "ircd.h"
33 #include "client.h"
34 #include "send.h"
35 #include "s_conf.h"
36 #include "s_newconf.h"
37 #include "numeric.h"
38 #include "parse.h"
39 #include "ircd_defs.h"
40 #include "irc_string.h"
41 #include "sprintf_irc.h"
42
43
44
45 /* -TimeMr14C:
46 * I have moved the dl* function definitions and
47 * the two functions (load_a_module / unload_a_module) to the
48 * file dynlink.c
49 * And also made the necessary changes to those functions
50 * to comply with shl_load and friends.
51 * In this file, to keep consistency with the makefile,
52 * I added the ability to load *.sl files, too.
53 * 27/02/2002
54 */
55
56 #ifndef STATIC_MODULES
57
58 struct module **modlist = NULL;
59
60 static const char *core_module_table[] = {
61 "m_die",
62 "m_error",
63 "m_join",
64 "m_kick",
65 "m_kill",
66 "m_message",
67 "m_mode",
68 "m_nick",
69 "m_part",
70 "m_quit",
71 "m_server",
72 "m_sjoin",
73 "m_squit",
74 NULL
75 };
76
77 #define MODS_INCREMENT 10
78 int num_mods = 0;
79 int max_mods = MODS_INCREMENT;
80
81 static rb_dlink_list mod_paths;
82
83 static int mo_modload(struct Client *, struct Client *, int, const char **);
84 static int mo_modlist(struct Client *, struct Client *, int, const char **);
85 static int mo_modreload(struct Client *, struct Client *, int, const char **);
86 static int mo_modunload(struct Client *, struct Client *, int, const char **);
87 static int mo_modrestart(struct Client *, struct Client *, int, const char **);
88
89 struct Message modload_msgtab = {
90 "MODLOAD", 0, 0, 0, MFLG_SLOW,
91 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modload, 2}}
92 };
93
94 struct Message modunload_msgtab = {
95 "MODUNLOAD", 0, 0, 0, MFLG_SLOW,
96 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modunload, 2}}
97 };
98
99 struct Message modreload_msgtab = {
100 "MODRELOAD", 0, 0, 0, MFLG_SLOW,
101 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modreload, 2}}
102 };
103
104 struct Message modlist_msgtab = {
105 "MODLIST", 0, 0, 0, MFLG_SLOW,
106 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modlist, 0}}
107 };
108
109 struct Message modrestart_msgtab = {
110 "MODRESTART", 0, 0, 0, MFLG_SLOW,
111 {mg_unreg, mg_not_oper, mg_ignore, mg_ignore, mg_ignore, {mo_modrestart, 0}}
112 };
113
114 extern struct Message error_msgtab;
115
116 void
117 modules_init(void)
118 {
119 mod_add_cmd(&modload_msgtab);
120 mod_add_cmd(&modunload_msgtab);
121 mod_add_cmd(&modreload_msgtab);
122 mod_add_cmd(&modlist_msgtab);
123 mod_add_cmd(&modrestart_msgtab);
124
125 /* Add the default paths we look in to the module system --nenolod */
126 mod_add_path(MODPATH);
127 mod_add_path(AUTOMODPATH);
128 }
129
130 /* mod_find_path()
131 *
132 * input - path
133 * output - none
134 * side effects - returns a module path from path
135 */
136 static struct module_path *
137 mod_find_path(const char *path)
138 {
139 rb_dlink_node *ptr;
140 struct module_path *mpath;
141
142 RB_DLINK_FOREACH(ptr, mod_paths.head)
143 {
144 mpath = ptr->data;
145
146 if(!strcmp(path, mpath->path))
147 return mpath;
148 }
149
150 return NULL;
151 }
152
153 /* mod_add_path
154 *
155 * input - path
156 * ouput -
157 * side effects - adds path to list
158 */
159 void
160 mod_add_path(const char *path)
161 {
162 struct module_path *pathst;
163
164 if(mod_find_path(path))
165 return;
166
167 pathst = rb_malloc(sizeof(struct module_path));
168
169 strcpy(pathst->path, path);
170 rb_dlinkAddAlloc(pathst, &mod_paths);
171 }
172
173 /* mod_clear_paths()
174 *
175 * input -
176 * output -
177 * side effects - clear the lists of paths
178 */
179 void
180 mod_clear_paths(void)
181 {
182 rb_dlink_node *ptr, *next_ptr;
183
184 RB_DLINK_FOREACH_SAFE(ptr, next_ptr, mod_paths.head)
185 {
186 rb_free(ptr->data);
187 free_rb_dlink_node(ptr);
188 }
189
190 mod_paths.head = mod_paths.tail = NULL;
191 mod_paths.length = 0;
192 }
193
194 /* irc_basename
195 *
196 * input -
197 * output -
198 * side effects -
199 */
200 char *
201 irc_basename(const char *path)
202 {
203 char *mod_basename = rb_malloc(strlen(path) + 1);
204 const char *s;
205
206 if(!(s = strrchr(path, '/')))
207 s = path;
208 else
209 s++;
210
211 (void) strcpy(mod_basename, s);
212 return mod_basename;
213 }
214
215 /* findmodule_byname
216 *
217 * input -
218 * output -
219 * side effects -
220 */
221
222 int
223 findmodule_byname(const char *name)
224 {
225 int i;
226
227 for (i = 0; i < num_mods; i++)
228 {
229 if(!irccmp(modlist[i]->name, name))
230 return i;
231 }
232 return -1;
233 }
234
235 /* load_all_modules()
236 *
237 * input -
238 * output -
239 * side effects -
240 */
241 void
242 load_all_modules(int warn)
243 {
244 DIR *system_module_dir = NULL;
245 struct dirent *ldirent = NULL;
246 char module_fq_name[PATH_MAX + 1];
247 int len;
248
249 modules_init();
250
251 modlist = (struct module **) rb_malloc(sizeof(struct module) * (MODS_INCREMENT));
252
253 max_mods = MODS_INCREMENT;
254
255 system_module_dir = opendir(AUTOMODPATH);
256
257 if(system_module_dir == NULL)
258 {
259 ilog(L_MAIN, "Could not load modules from %s: %s", AUTOMODPATH, strerror(errno));
260 return;
261 }
262
263 while ((ldirent = readdir(system_module_dir)) != NULL)
264 {
265 len = strlen(ldirent->d_name);
266 if((len > 3) && !strcmp(ldirent->d_name+len-3, SHARED_SUFFIX))
267 {
268 (void) rb_snprintf(module_fq_name, sizeof(module_fq_name), "%s/%s", AUTOMODPATH, ldirent->d_name);
269 (void) load_a_module(module_fq_name, warn, 0);
270 }
271
272 }
273 (void) closedir(system_module_dir);
274 }
275
276 /* load_core_modules()
277 *
278 * input -
279 * output -
280 * side effects - core modules are loaded, if any fail, kill ircd
281 */
282 void
283 load_core_modules(int warn)
284 {
285 char module_name[MAXPATHLEN];
286 int i;
287
288
289 for (i = 0; core_module_table[i]; i++)
290 {
291 rb_snprintf(module_name, sizeof(module_name), "%s/%s%s", MODPATH,
292 core_module_table[i], SHARED_SUFFIX);
293
294 if(load_a_module(module_name, warn, 1) == -1)
295 {
296 ilog(L_MAIN,
297 "Error loading core module %s%s: terminating ircd",
298 core_module_table[i], SHARED_SUFFIX);
299 exit(0);
300 }
301 }
302 }
303
304 /* load_one_module()
305 *
306 * input -
307 * output -
308 * side effects -
309 */
310 int
311 load_one_module(const char *path, int coremodule)
312 {
313 char modpath[MAXPATHLEN];
314 rb_dlink_node *pathst;
315 struct module_path *mpath;
316
317 struct stat statbuf;
318
319 if (server_state_foreground == 1)
320 inotice("loading module %s ...", path);
321
322 RB_DLINK_FOREACH(pathst, mod_paths.head)
323 {
324 mpath = pathst->data;
325
326 rb_snprintf(modpath, sizeof(modpath), "%s/%s", mpath->path, path);
327 if((strstr(modpath, "../") == NULL) && (strstr(modpath, "/..") == NULL))
328 {
329 if(stat(modpath, &statbuf) == 0)
330 {
331 if(S_ISREG(statbuf.st_mode))
332 {
333 /* Regular files only please */
334 if(coremodule)
335 return load_a_module(modpath, 1, 1);
336 else
337 return load_a_module(modpath, 1, 0);
338 }
339 }
340
341 }
342 }
343
344 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Cannot locate module %s", path);
345 return -1;
346 }
347
348
349 /* load a module .. */
350 static int
351 mo_modload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
352 {
353 char *m_bn;
354
355 if(!IsOperAdmin(source_p))
356 {
357 sendto_one(source_p, form_str(ERR_NOPRIVS),
358 me.name, source_p->name, "admin");
359 return 0;
360 }
361
362 m_bn = irc_basename(parv[1]);
363
364 if(findmodule_byname(m_bn) != -1)
365 {
366 sendto_one_notice(source_p, ":Module %s is already loaded", m_bn);
367 rb_free(m_bn);
368 return 0;
369 }
370
371 load_one_module(parv[1], 0);
372
373 rb_free(m_bn);
374
375 return 0;
376 }
377
378
379 /* unload a module .. */
380 static int
381 mo_modunload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
382 {
383 char *m_bn;
384 int modindex;
385
386 if(!IsOperAdmin(source_p))
387 {
388 sendto_one(source_p, form_str(ERR_NOPRIVS),
389 me.name, source_p->name, "admin");
390 return 0;
391 }
392
393 m_bn = irc_basename(parv[1]);
394
395 if((modindex = findmodule_byname(m_bn)) == -1)
396 {
397 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
398 rb_free(m_bn);
399 return 0;
400 }
401
402 if(modlist[modindex]->core == 1)
403 {
404 sendto_one_notice(source_p, ":Module %s is a core module and may not be unloaded", m_bn);
405 rb_free(m_bn);
406 return 0;
407 }
408
409 if(unload_one_module(m_bn, 1) == -1)
410 {
411 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
412 }
413
414 rb_free(m_bn);
415 return 0;
416 }
417
418 /* unload and load in one! */
419 static int
420 mo_modreload(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
421 {
422 char *m_bn;
423 int modindex;
424 int check_core;
425
426 if(!IsOperAdmin(source_p))
427 {
428 sendto_one(source_p, form_str(ERR_NOPRIVS),
429 me.name, source_p->name, "admin");
430 return 0;
431 }
432
433 m_bn = irc_basename(parv[1]);
434
435 if((modindex = findmodule_byname(m_bn)) == -1)
436 {
437 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
438 rb_free(m_bn);
439 return 0;
440 }
441
442 check_core = modlist[modindex]->core;
443
444 if(unload_one_module(m_bn, 1) == -1)
445 {
446 sendto_one_notice(source_p, ":Module %s is not loaded", m_bn);
447 rb_free(m_bn);
448 return 0;
449 }
450
451 if((load_one_module(parv[1], check_core) == -1) && check_core)
452 {
453 sendto_realops_snomask(SNO_GENERAL, L_ALL,
454 "Error reloading core module: %s: terminating ircd", parv[1]);
455 ilog(L_MAIN, "Error loading core module %s: terminating ircd", parv[1]);
456 exit(0);
457 }
458
459 rb_free(m_bn);
460 return 0;
461 }
462
463 /* list modules .. */
464 static int
465 mo_modlist(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
466 {
467 int i;
468
469 if(!IsOperAdmin(source_p))
470 {
471 sendto_one(source_p, form_str(ERR_NOPRIVS),
472 me.name, source_p->name, "admin");
473 return 0;
474 }
475
476 for (i = 0; i < num_mods; i++)
477 {
478 if(parc > 1)
479 {
480 if(match(parv[1], modlist[i]->name))
481 {
482 sendto_one(source_p, form_str(RPL_MODLIST),
483 me.name, source_p->name,
484 modlist[i]->name,
485 modlist[i]->address,
486 modlist[i]->version, modlist[i]->core ? "(core)" : "");
487 }
488 }
489 else
490 {
491 sendto_one(source_p, form_str(RPL_MODLIST),
492 me.name, source_p->name, modlist[i]->name,
493 modlist[i]->address, modlist[i]->version,
494 modlist[i]->core ? "(core)" : "");
495 }
496 }
497
498 sendto_one(source_p, form_str(RPL_ENDOFMODLIST), me.name, source_p->name);
499 return 0;
500 }
501
502 /* unload and reload all modules */
503 static int
504 mo_modrestart(struct Client *client_p, struct Client *source_p, int parc, const char **parv)
505 {
506 int modnum;
507
508 if(!IsOperAdmin(source_p))
509 {
510 sendto_one(source_p, form_str(ERR_NOPRIVS),
511 me.name, source_p->name, "admin");
512 return 0;
513 }
514
515 sendto_one_notice(source_p, ":Reloading all modules");
516
517 modnum = num_mods;
518 while (num_mods)
519 unload_one_module(modlist[0]->name, 0);
520
521 load_all_modules(0);
522 load_core_modules(0);
523 rehash(0);
524
525 sendto_realops_snomask(SNO_GENERAL, L_ALL,
526 "Module Restart: %d modules unloaded, %d modules loaded",
527 modnum, num_mods);
528 ilog(L_MAIN, "Module Restart: %d modules unloaded, %d modules loaded", modnum, num_mods);
529 return 0;
530 }
531
532
533
534 #ifndef RTLD_NOW
535 #define RTLD_NOW RTLD_LAZY /* openbsd deficiency */
536 #endif
537
538 #ifdef CHARYBDIS_PROFILE
539 # ifndef RTLD_PROFILE
540 # warning libdl may not support profiling, sucks. :(
541 # define RTLD_PROFILE 0
542 # endif
543 #endif
544
545 static void increase_modlist(void);
546
547 #define MODS_INCREMENT 10
548
549 static char unknown_ver[] = "<unknown>";
550
551 /* This file contains the core functions to use dynamic libraries.
552 * -TimeMr14C
553 */
554
555
556 #ifdef HAVE_MACH_O_DYLD_H
557 /*
558 ** jmallett's dl*(3) shims for NSModule(3) systems.
559 */
560 #include <mach-o/dyld.h>
561
562 #ifndef HAVE_DLOPEN
563 #ifndef RTLD_LAZY
564 #define RTLD_LAZY 2185 /* built-in dl*(3) don't care */
565 #endif
566
567 void undefinedErrorHandler(const char *);
568 NSModule multipleErrorHandler(NSSymbol, NSModule, NSModule);
569 void linkEditErrorHandler(NSLinkEditErrors, int, const char *, const char *);
570 char *dlerror(void);
571 void *dlopen(char *, int);
572 int dlclose(void *);
573 void *dlsym(void *, char *);
574
575 static int firstLoad = TRUE;
576 static int myDlError;
577 static char *myErrorTable[] = { "Loading file as object failed\n",
578 "Loading file as object succeeded\n",
579 "Not a valid shared object\n",
580 "Architecture of object invalid on this architecture\n",
581 "Invalid or corrupt image\n",
582 "Could not access object\n",
583 "NSCreateObjectFileImageFromFile failed\n",
584 NULL
585 };
586
587 void
588 undefinedErrorHandler(const char *symbolName)
589 {
590 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Undefined symbol: %s", symbolName);
591 ilog(L_MAIN, "Undefined symbol: %s", symbolName);
592 return;
593 }
594
595 NSModule
596 multipleErrorHandler(NSSymbol s, NSModule old, NSModule new)
597 {
598 /* XXX
599 ** This results in substantial leaking of memory... Should free one
600 ** module, maybe?
601 */
602 sendto_realops_snomask(SNO_GENERAL, L_ALL,
603 "Symbol `%s' found in `%s' and `%s'",
604 NSNameOfSymbol(s), NSNameOfModule(old), NSNameOfModule(new));
605 ilog(L_MAIN, "Symbol `%s' found in `%s' and `%s'",
606 NSNameOfSymbol(s), NSNameOfModule(old), NSNameOfModule(new));
607 /* We return which module should be considered valid, I believe */
608 return new;
609 }
610
611 void
612 linkEditErrorHandler(NSLinkEditErrors errorClass, int errnum,
613 const char *fileName, const char *errorString)
614 {
615 sendto_realops_snomask(SNO_GENERAL, L_ALL,
616 "Link editor error: %s for %s", errorString, fileName);
617 ilog(L_MAIN, "Link editor error: %s for %s", errorString, fileName);
618 return;
619 }
620
621 char *
622 dlerror(void)
623 {
624 return myDlError == NSObjectFileImageSuccess ? NULL : myErrorTable[myDlError % 7];
625 }
626
627 void *
628 dlopen(char *filename, int unused)
629 {
630 NSObjectFileImage myImage;
631 NSModule myModule;
632
633 if(firstLoad)
634 {
635 /*
636 ** If we are loading our first symbol (huzzah!) we should go ahead
637 ** and install link editor error handling!
638 */
639 NSLinkEditErrorHandlers linkEditorErrorHandlers;
640
641 linkEditorErrorHandlers.undefined = undefinedErrorHandler;
642 linkEditorErrorHandlers.multiple = multipleErrorHandler;
643 linkEditorErrorHandlers.linkEdit = linkEditErrorHandler;
644 NSInstallLinkEditErrorHandlers(&linkEditorErrorHandlers);
645 firstLoad = FALSE;
646 }
647 myDlError = NSCreateObjectFileImageFromFile(filename, &myImage);
648 if(myDlError != NSObjectFileImageSuccess)
649 {
650 return NULL;
651 }
652 myModule = NSLinkModule(myImage, filename, NSLINKMODULE_OPTION_PRIVATE);
653 return (void *) myModule;
654 }
655
656 int
657 dlclose(void *myModule)
658 {
659 NSUnLinkModule(myModule, FALSE);
660 return 0;
661 }
662
663 void *
664 dlsym(void *myModule, char *mySymbolName)
665 {
666 NSSymbol mySymbol;
667
668 mySymbol = NSLookupSymbolInModule((NSModule) myModule, mySymbolName);
669 return NSAddressOfSymbol(mySymbol);
670 }
671 #endif
672 #endif
673
674
675 /*
676 * HPUX dl compat functions
677 */
678 #if defined(HAVE_SHL_LOAD) && !defined(HAVE_DLOPEN)
679 #define RTLD_LAZY BIND_DEFERRED
680 #define RTLD_GLOBAL DYNAMIC_PATH
681 #define dlopen(file,mode) (void *)shl_load((file), (mode), (long) 0)
682 #define dlclose(handle) shl_unload((shl_t)(handle))
683 #define dlsym(handle,name) hpux_dlsym(handle,name)
684 #define dlerror() strerror(errno)
685
686 static void *
687 hpux_dlsym(void *handle, char *name)
688 {
689 void *sym_addr;
690 if(!shl_findsym((shl_t *) & handle, name, TYPE_UNDEFINED, &sym_addr))
691 return sym_addr;
692 return NULL;
693 }
694
695 #endif
696
697 /* unload_one_module()
698 *
699 * inputs - name of module to unload
700 * - 1 to say modules unloaded, 0 to not
701 * output - 0 if successful, -1 if error
702 * side effects - module is unloaded
703 */
704 int
705 unload_one_module(const char *name, int warn)
706 {
707 int modindex;
708
709 if((modindex = findmodule_byname(name)) == -1)
710 return -1;
711
712 /*
713 ** XXX - The type system in C does not allow direct conversion between
714 ** data and function pointers, but as it happens, most C compilers will
715 ** safely do this, however it is a theoretical overlow to cast as we
716 ** must do here. I have library functions to take care of this, but
717 ** despite being more "correct" for the C language, this is more
718 ** practical. Removing the abuse of the ability to cast ANY pointer
719 ** to and from an integer value here will break some compilers.
720 ** -jmallett
721 */
722 /* Left the comment in but the code isn't here any more -larne */
723 switch (modlist[modindex]->mapi_version)
724 {
725 case 1:
726 {
727 struct mapi_mheader_av1 *mheader = modlist[modindex]->mapi_header;
728 if(mheader->mapi_command_list)
729 {
730 struct Message **m;
731 for (m = mheader->mapi_command_list; *m; ++m)
732 mod_del_cmd(*m);
733 }
734
735 /* hook events are never removed, we simply lose the
736 * ability to call them --fl
737 */
738 if(mheader->mapi_hfn_list)
739 {
740 mapi_hfn_list_av1 *m;
741 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
742 remove_hook(m->hapi_name, m->fn);
743 }
744
745 if(mheader->mapi_unregister)
746 mheader->mapi_unregister();
747 break;
748 }
749 default:
750 sendto_realops_snomask(SNO_GENERAL, L_ALL,
751 "Unknown/unsupported MAPI version %d when unloading %s!",
752 modlist[modindex]->mapi_version, modlist[modindex]->name);
753 ilog(L_MAIN, "Unknown/unsupported MAPI version %d when unloading %s!",
754 modlist[modindex]->mapi_version, modlist[modindex]->name);
755 break;
756 }
757
758 dlclose(modlist[modindex]->address);
759
760 rb_free(modlist[modindex]->name);
761 memcpy(&modlist[modindex], &modlist[modindex + 1],
762 sizeof(struct module) * ((num_mods - 1) - modindex));
763
764 if(num_mods != 0)
765 num_mods--;
766
767 if(warn == 1)
768 {
769 ilog(L_MAIN, "Module %s unloaded", name);
770 sendto_realops_snomask(SNO_GENERAL, L_ALL, "Module %s unloaded", name);
771 }
772
773 return 0;
774 }
775
776
777 /*
778 * load_a_module()
779 *
780 * inputs - path name of module, int to notice, int of core
781 * output - -1 if error 0 if success
782 * side effects - loads a module if successful
783 */
784 int
785 load_a_module(const char *path, int warn, int core)
786 {
787 void *tmpptr = NULL;
788
789 char *mod_basename;
790 const char *ver;
791
792 int *mapi_version;
793
794 mod_basename = irc_basename(path);
795
796 #ifdef CHARYBDIS_PROFILE
797 tmpptr = dlopen(path, RTLD_NOW | RTLD_PROFILE);
798 #else
799 tmpptr = dlopen(path, RTLD_NOW);
800 #endif
801
802 if(tmpptr == NULL)
803 {
804 const char *err = dlerror();
805
806 sendto_realops_snomask(SNO_GENERAL, L_ALL,
807 "Error loading module %s: %s", mod_basename, err);
808 ilog(L_MAIN, "Error loading module %s: %s", mod_basename, err);
809 rb_free(mod_basename);
810 return -1;
811 }
812
813
814 /*
815 * _mheader is actually a struct mapi_mheader_*, but mapi_version
816 * is always the first member of this structure, so we treate it
817 * as a single int in order to determine the API version.
818 * -larne.
819 */
820 mapi_version = (int *) (uintptr_t) dlsym(tmpptr, "_mheader");
821 if((mapi_version == NULL
822 && (mapi_version = (int *) (uintptr_t) dlsym(tmpptr, "__mheader")) == NULL)
823 || MAPI_MAGIC(*mapi_version) != MAPI_MAGIC_HDR)
824 {
825 sendto_realops_snomask(SNO_GENERAL, L_ALL,
826 "Data format error: module %s has no MAPI header.",
827 mod_basename);
828 ilog(L_MAIN, "Data format error: module %s has no MAPI header.", mod_basename);
829 (void) dlclose(tmpptr);
830 rb_free(mod_basename);
831 return -1;
832 }
833
834 switch (MAPI_VERSION(*mapi_version))
835 {
836 case 1:
837 {
838 struct mapi_mheader_av1 *mheader = (struct mapi_mheader_av1 *) mapi_version; /* see above */
839 if(mheader->mapi_register && (mheader->mapi_register() == -1))
840 {
841 ilog(L_MAIN, "Module %s indicated failure during load.",
842 mod_basename);
843 sendto_realops_snomask(SNO_GENERAL, L_ALL,
844 "Module %s indicated failure during load.",
845 mod_basename);
846 dlclose(tmpptr);
847 rb_free(mod_basename);
848 return -1;
849 }
850 if(mheader->mapi_command_list)
851 {
852 struct Message **m;
853 for (m = mheader->mapi_command_list; *m; ++m)
854 mod_add_cmd(*m);
855 }
856
857 if(mheader->mapi_hook_list)
858 {
859 mapi_hlist_av1 *m;
860 for (m = mheader->mapi_hook_list; m->hapi_name; ++m)
861 *m->hapi_id = register_hook(m->hapi_name);
862 }
863
864 if(mheader->mapi_hfn_list)
865 {
866 mapi_hfn_list_av1 *m;
867 for (m = mheader->mapi_hfn_list; m->hapi_name; ++m)
868 add_hook(m->hapi_name, m->fn);
869 }
870
871 ver = mheader->mapi_module_version;
872 break;
873 }
874
875 default:
876 ilog(L_MAIN, "Module %s has unknown/unsupported MAPI version %d.",
877 mod_basename, MAPI_VERSION(*mapi_version));
878 sendto_realops_snomask(SNO_GENERAL, L_ALL,
879 "Module %s has unknown/unsupported MAPI version %d.",
880 mod_basename, *mapi_version);
881 dlclose(tmpptr);
882 rb_free(mod_basename);
883 return -1;
884 }
885
886 if(ver == NULL)
887 ver = unknown_ver;
888
889 increase_modlist();
890
891 modlist[num_mods] = rb_malloc(sizeof(struct module));
892 modlist[num_mods]->address = tmpptr;
893 modlist[num_mods]->version = ver;
894 modlist[num_mods]->core = core;
895 modlist[num_mods]->name = rb_strdup(mod_basename);
896 modlist[num_mods]->mapi_header = mapi_version;
897 modlist[num_mods]->mapi_version = MAPI_VERSION(*mapi_version);
898 num_mods++;
899
900 if(warn == 1)
901 {
902 sendto_realops_snomask(SNO_GENERAL, L_ALL,
903 "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
904 mod_basename, ver, MAPI_VERSION(*mapi_version),
905 (unsigned long) tmpptr);
906 ilog(L_MAIN, "Module %s [version: %s; MAPI version: %d] loaded at 0x%lx",
907 mod_basename, ver, MAPI_VERSION(*mapi_version), (unsigned long) tmpptr);
908 }
909 rb_free(mod_basename);
910 return 0;
911 }
912
913 /*
914 * increase_modlist
915 *
916 * inputs - NONE
917 * output - NONE
918 * side effects - expand the size of modlist if necessary
919 */
920 static void
921 increase_modlist(void)
922 {
923 struct module **new_modlist = NULL;
924
925 if((num_mods + 1) < max_mods)
926 return;
927
928 new_modlist = (struct module **) rb_malloc(sizeof(struct module) *
929 (max_mods + MODS_INCREMENT));
930 memcpy((void *) new_modlist, (void *) modlist, sizeof(struct module) * num_mods);
931
932 rb_free(modlist);
933 modlist = new_modlist;
934 max_mods += MODS_INCREMENT;
935 }
936
937 #else /* STATIC_MODULES */
938
939 /* load_all_modules()
940 *
941 * input -
942 * output -
943 * side effects - all the msgtabs are added for static modules
944 */
945 void
946 load_all_modules(int warn)
947 {
948 load_static_modules();
949 }
950
951 #endif /* STATIC_MODULES */